• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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        client_1.srp_client_set_host_name('my-host-1')
105        client_1.srp_client_set_host_address('2001::1')
106        client_1.srp_client_start(server.get_addrs()[0], client_1.get_srp_server_port())
107        client_1.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
108        self.simulator.go(2)
109
110        # Verify that the client possesses correct service resources.
111        client_1_service = client_1.srp_client_get_services()[0]
112        self.assertEqual(client_1_service['instance'], 'my-service-1')
113        self.assertEqual(client_1_service['name'], '_ipps._tcp')
114        self.assertEqual(int(client_1_service['port']), 12345)
115        self.assertEqual(int(client_1_service['priority']), 0)
116        self.assertEqual(int(client_1_service['weight']), 0)
117
118        # Verify that the client receives a SUCCESS response for the server.
119        self.assertEqual(client_1_service['state'], 'Registered')
120
121        # Verify that the server accepts the SRP registration and stored
122        # the same service resources.
123        server_service = server.srp_server_get_services()[0]
124        self.assertEqual(server_service['deleted'], 'false')
125        self.assertEqual(server_service['instance'], client_1_service['instance'])
126        self.assertEqual(server_service['name'], client_1_service['name'])
127        self.assertEqual(int(server_service['port']), int(client_1_service['port']))
128        self.assertEqual(int(server_service['priority']), int(client_1_service['priority']))
129        self.assertEqual(int(server_service['weight']), int(client_1_service['weight']))
130        self.assertEqual(server_service['host'], 'my-host-1')
131
132        server_host = server.srp_server_get_hosts()[0]
133        self.assertEqual(server_host['deleted'], 'false')
134        self.assertEqual(server_host['fullname'], server_service['host_fullname'])
135        self.assertEqual(len(server_host['addresses']), 1)
136        self.assertEqual(ipaddress.ip_address(server_host['addresses'][0]), ipaddress.ip_address('2001::1'))
137
138        #
139        # 2. Register with the same host name from the second client and it should fail.
140        #
141
142        client_2.srp_client_set_host_name('my-host-1')
143        client_2.srp_client_set_host_address('2001::2')
144        client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port())
145        client_2.srp_client_add_service('my-service-2', '_ipps._tcp', 12345)
146        self.simulator.go(2)
147
148        # It is expected that the registration will be rejected.
149        client_2_service = client_2.srp_client_get_services()[0]
150        self.assertNotEqual(client_2_service['state'], 'Registered')
151        self.assertNotEqual(client_2.srp_client_get_host_state(), 'Registered')
152
153        self.assertEqual(len(server.srp_server_get_services()), 1)
154        self.assertEqual(len(server.srp_server_get_hosts()), 1)
155
156        client_2.srp_client_clear_host()
157        client_2.srp_client_stop()
158
159        #
160        # 3. Register with the same service name from the second client and it should fail.
161        #
162
163        client_2.srp_client_set_host_name('my-host-2')
164        client_2.srp_client_set_host_address('2001::2')
165        client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port())
166        client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
167        self.simulator.go(2)
168
169        # It is expected that the registration will be rejected.
170        client_2_service = client_2.srp_client_get_services()[0]
171        self.assertNotEqual(client_2_service['state'], 'Registered')
172        self.assertNotEqual(client_2.srp_client_get_host_state(), 'Registered')
173
174        self.assertEqual(len(server.srp_server_get_services()), 1)
175        self.assertEqual(len(server.srp_server_get_hosts()), 1)
176
177        client_2.srp_client_clear_host()
178        client_2.srp_client_stop()
179
180        #
181        # 4. Register the same service instance label with a different service name
182        # from the second client and it should pass.
183        #
184
185        client_2.srp_client_set_host_name('my-host-2')
186        client_2.srp_client_set_host_address('2001::2')
187        client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port())
188        client_2.srp_client_add_service('my-service-1', '_ipps2._tcp', 12345)
189        self.simulator.go(2)
190
191        # It is expected that the registration will be accepted.
192        client_2_service = client_2.srp_client_get_services()[0]
193        self.assertEqual(client_2_service['state'], 'Registered')
194        self.assertEqual(client_2.srp_client_get_host_state(), 'Registered')
195
196        self.assertEqual(len(server.srp_server_get_services()), 2)
197        self.assertEqual(len(server.srp_server_get_hosts()), 2)
198        self.assertEqual(server.srp_server_get_host('my-host-2')['deleted'], 'false')
199        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps2._tcp')['deleted'], 'false')
200
201        # Remove the host and all services registered on the SRP server.
202        client_2.srp_client_remove_host(remove_key=True)
203        self.simulator.go(2)
204
205        client_2.srp_client_clear_host()
206        client_2.srp_client_stop()
207
208        #
209        # 5. Register with different host & service instance name, it should succeed.
210        #
211
212        client_2.srp_client_set_host_name('my-host-2')
213        client_2.srp_client_set_host_address('2001::2')
214        client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port())
215        client_2.srp_client_add_service('my-service-2', '_ipps._tcp', 12345)
216        self.simulator.go(2)
217
218        # It is expected that the registration will be accepted.
219        client_2_service = client_2.srp_client_get_services()[0]
220        self.assertEqual(client_2_service['state'], 'Registered')
221        self.assertEqual(client_2.srp_client_get_host_state(), 'Registered')
222
223        self.assertEqual(len(server.srp_server_get_services()), 2)
224        self.assertEqual(len(server.srp_server_get_hosts()), 2)
225        self.assertEqual(server.srp_server_get_host('my-host-2')['deleted'], 'false')
226        self.assertEqual(server.srp_server_get_service('my-service-2', '_ipps._tcp')['deleted'], 'false')
227
228        # Remove the host and all services registered on the SRP server.
229        client_2.srp_client_remove_host(remove_key=True)
230        self.simulator.go(2)
231
232        client_2.srp_client_clear_host()
233        client_2.srp_client_stop()
234
235        #
236        # 6. Register with the same service instance full name before its KEY LEASE expires,
237        #    it is expected to fail.
238        #
239
240        # Remove the service instance from SRP server but retains its name.
241        client_1.srp_client_remove_service('my-service-1', '_ipps._tcp')
242        self.simulator.go(2)
243
244        client_2.srp_client_set_host_name('my-host-2')
245        client_2.srp_client_set_host_address('2001::2')
246        client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port())
247        client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
248        self.simulator.go(2)
249
250        # It is expected that the registration will be rejected.
251        client_2_service = client_2.srp_client_get_services()[0]
252        self.assertNotEqual(client_2_service['state'], 'Registered')
253        self.assertNotEqual(client_2.srp_client_get_host_state(), 'Registered')
254
255        # The service 'my-service-1' is removed but its name is retained.
256        # This is why we can see the service record on the SRP server.
257        self.assertEqual(len(server.srp_server_get_services()), 1)
258        self.assertEqual(len(server.srp_server_get_hosts()), 1)
259        self.assertEqual(server.srp_server_get_host('my-host-1')['deleted'], 'false')
260        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps._tcp')['deleted'], 'true')
261
262        client_2.srp_client_clear_host()
263        client_2.srp_client_stop()
264
265        #
266        # 7. The service instance name can be re-used by another client when
267        #    the service has been permanently removed (the KEY resource is
268        #    removed) from the host.
269        #
270
271        # Client 1 adds back the service, it should success.
272        client_1.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
273        self.simulator.go(2)
274        self.assertEqual(len(server.srp_server_get_services()), 1)
275        self.assertEqual(len(server.srp_server_get_hosts()), 1)
276        self.assertEqual(server.srp_server_get_host('my-host-1')['deleted'], 'false')
277        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps._tcp')['deleted'], 'false')
278
279        # Permanently removes the service instance.
280        client_1.srp_client_remove_host(remove_key=True)
281        self.simulator.go(2)
282        self.assertEqual(len(server.srp_server_get_services()), 0)
283        self.assertEqual(len(server.srp_server_get_hosts()), 0)
284
285        # Client 2 registers the same host & service instance name with Client 1.
286        client_2.srp_client_stop()
287        client_2.srp_client_clear_host()
288        client_2.srp_client_set_host_name('my-host-1')
289        client_2.srp_client_set_host_address('2001::2')
290        client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port())
291        client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345)
292        self.simulator.go(2)
293
294        # It is expected that client 2 will success because those names has been
295        # released by client 1.
296        self.assertEqual(len(server.srp_server_get_services()), 1)
297        self.assertEqual(len(server.srp_server_get_hosts()), 1)
298        self.assertEqual(server.srp_server_get_host('my-host-1')['deleted'], 'false')
299        self.assertEqual(server.srp_server_get_service('my-service-1', '_ipps._tcp')['deleted'], 'false')
300
301
302if __name__ == '__main__':
303    unittest.main()
304