1 // Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 #include <asiolink/io_address.h>
9 #include <dhcp/docsis3_option_defs.h>
10 #include <dhcp/option6_addrlst.h>
11 #include <dhcp/option_int.h>
12 #include <dhcp/option_vendor.h>
13 #include <dhcp/tests/iface_mgr_test_config.h>
14 #include <dhcp6/tests/dhcp6_test_utils.h>
15 #include <dhcp6/tests/dhcp6_client.h>
16 #include <boost/algorithm/string/join.hpp>
17 #include <boost/lexical_cast.hpp>
18 #include <functional>
19 #include <list>
20 #include <sstream>
21 
22 using namespace isc;
23 using namespace isc::asiolink;
24 using namespace isc::dhcp;
25 using namespace isc::dhcp::test;
26 
27 namespace {
28 
29 /// @brief Set of JSON configurations used by the Host reservation unit tests.
30 ///
31 /// - Configuration 0:
32 ///   Single subnet with two reservations, one with a hostname, one without
33 ///
34 /// - Configuration 1:
35 ///   Multiple reservations using different host identifiers.
36 ///
37 /// - Configuration 2:
38 ///   Same as configuration 1 but 'host-reservation-identifiers' specified
39 ///   in non-default order.
40 ///
41 /// - Configuration 3:
42 ///   - Used to test that host specific options override pool specific,
43 ///     subnet specific and global options.
44 ///
45 /// - Configuration 4:
46 ///   - Used to test that client receives options solely specified in a
47 ///     host scope.
48 ///
49 /// - Configuration 5:
50 ///   - Used to test that host specific vendor options override globally
51 ///     specified vendor options.
52 ///
53 /// - Configuration 6:
54 ///   - One subnet with very short pool, i.e. two addresses
55 ///
56 /// - Configuration 7:
57 ///   - Similar to Configuration 6, but one of the addresses reserved to client
58 ///     with the DUID 04:03:02:01.
59 ///
60 /// Descriptions of next configurations are in the comment with the number.
61 const char* CONFIGS[] = {
62     // Configuration 0:
63     "{ "
64         "\"interfaces-config\": {"
65         "  \"interfaces\": [ \"*\" ]"
66         "},"
67         "\"valid-lifetime\": 4000, "
68         "\"preferred-lifetime\": 3000,"
69         "\"rebind-timer\": 2000, "
70         "\"renew-timer\": 1000, "
71         "\"subnet6\": [ "
72         " { "
73         "    \"subnet\": \"2001:db8:1::/48\", "
74         "    \"pools\": [ { \"pool\": \"2001:db8:1:1::/64\" } ],"
75         "    \"interface\" : \"eth0\" , "
76         "    \"reservations\": ["
77         "    {"
78         "        \"duid\": \"01:02:03:04\","
79         "        \"ip-addresses\": [ \"2001:db8:1:1::babe\" ],"
80         "        \"hostname\": \"alice\""
81         "    },"
82         "    {"
83         "        \"duid\": \"01:02:03:05\","
84         "        \"ip-addresses\": [ \"2001:db8:1:1::babf\" ]"
85         "    } ]"
86         " } ]"
87    "}",
88 
89     // Configuration 1:
90     "{ "
91         "\"interfaces-config\": {"
92         "  \"interfaces\": [ \"*\" ]"
93         "},"
94         "\"valid-lifetime\": 4000, "
95         "\"preferred-lifetime\": 3000,"
96         "\"rebind-timer\": 2000, "
97         "\"renew-timer\": 1000, "
98         "\"mac-sources\": [ \"ipv6-link-local\" ], "
99         "\"subnet6\": [ "
100         " { "
101         "    \"subnet\": \"2001:db8:1::/48\", "
102         "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
103         "    \"interface\" : \"eth0\" , "
104         "    \"reservations\": ["
105         "    {"
106         "        \"hw-address\": \"38:60:77:d5:ff:ee\","
107         "        \"ip-addresses\": [ \"2001:db8:1::1\" ]"
108         "    },"
109         "    {"
110         "        \"duid\": \"01:02:03:05\","
111         "        \"ip-addresses\": [ \"2001:db8:1::2\" ]"
112         "    } ]"
113         " } ]"
114     "}",
115 
116     // Configuration 2:
117     "{ "
118         "\"interfaces-config\": {"
119         "  \"interfaces\": [ \"*\" ]"
120         "},"
121         "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ],"
122         "\"valid-lifetime\": 4000, "
123         "\"preferred-lifetime\": 3000,"
124         "\"rebind-timer\": 2000, "
125         "\"renew-timer\": 1000, "
126         "\"mac-sources\": [ \"ipv6-link-local\" ], "
127         "\"subnet6\": [ "
128         " { "
129         "    \"subnet\": \"2001:db8:1::/48\", "
130         "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
131         "    \"interface\" : \"eth0\" , "
132         "    \"reservations\": ["
133         "    {"
134         "        \"hw-address\": \"38:60:77:d5:ff:ee\","
135         "        \"ip-addresses\": [ \"2001:db8:1::1\" ]"
136         "    },"
137         "    {"
138         "        \"duid\": \"01:02:03:05\","
139         "        \"ip-addresses\": [ \"2001:db8:1::2\" ]"
140         "    } ]"
141         " } ]"
142     "}",
143 
144     // Configuration 3:
145     "{ "
146         "\"interfaces-config\": {"
147         "  \"interfaces\": [ \"*\" ]"
148         "},"
149         "\"host-reservation-identifiers\": [ \"duid\" ],"
150         "\"valid-lifetime\": 4000, "
151         "\"preferred-lifetime\": 3000,"
152         "\"rebind-timer\": 2000, "
153         "\"renew-timer\": 1000, "
154         "\"option-data\": [ {"
155         "    \"name\": \"nisp-servers\","
156         "    \"data\": \"3000:3::123\""
157         "} ],"
158         "\"subnet6\": [ "
159         " { "
160         "    \"subnet\": \"2001:db8:1::/48\", "
161         "    \"pools\": [ {"
162         "        \"pool\": \"2001:db8:1::/64\","
163         "        \"option-data\": [ {"
164         "            \"name\": \"dns-servers\","
165         "            \"data\": \"3000:2::111\""
166         "        } ]"
167         "    } ],"
168         "    \"interface\" : \"eth0\","
169         "    \"option-data\": [ {"
170         "        \"name\": \"dns-servers\","
171         "        \"data\": \"3000:2::123\""
172         "    },"
173         "    {"
174         "        \"name\": \"nis-servers\","
175         "        \"data\": \"3000:2::123\""
176         "    },"
177         "    {"
178         "        \"name\": \"sntp-servers\","
179         "        \"data\": \"3000:2::123\""
180         "    } ],"
181         "    \"reservations\": ["
182         "    {"
183         "        \"duid\": \"01:02:03:05\","
184         "        \"ip-addresses\": [ \"2001:db8:1::2\" ],"
185         "        \"option-data\": [ {"
186         "            \"name\": \"dns-servers\","
187         "            \"data\": \"3000:1::234\""
188         "        },"
189         "        {"
190         "            \"name\": \"nis-servers\","
191         "            \"data\": \"3000:1::234\""
192         "        } ]"
193         "    } ]"
194         " } ]"
195     "}",
196 
197     // Configuration 4:
198     "{ "
199         "\"interfaces-config\": {"
200         "  \"interfaces\": [ \"*\" ]"
201         "},"
202         "\"host-reservation-identifiers\": [ \"duid\" ],"
203         "\"valid-lifetime\": 4000, "
204         "\"preferred-lifetime\": 3000,"
205         "\"rebind-timer\": 2000, "
206         "\"renew-timer\": 1000, "
207         "\"subnet6\": [ "
208         " { "
209         "    \"subnet\": \"2001:db8:1::/48\", "
210         "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
211         "    \"interface\" : \"eth0\","
212         "    \"reservations\": ["
213         "    {"
214         "        \"duid\": \"01:02:03:05\","
215         "        \"ip-addresses\": [ \"2001:db8:1::2\" ],"
216         "        \"option-data\": [ {"
217         "            \"name\": \"dns-servers\","
218         "            \"data\": \"3000:1::234\""
219         "        },"
220         "        {"
221         "            \"name\": \"nis-servers\","
222         "            \"data\": \"3000:1::234\""
223         "        } ]"
224         "    } ]"
225         " } ]"
226     "}",
227 
228     // Configuration 5:
229     "{ "
230         "\"interfaces-config\": {"
231         "  \"interfaces\": [ \"*\" ]"
232         "},"
233         "\"host-reservation-identifiers\": [ \"duid\" ],"
234         "\"valid-lifetime\": 4000, "
235         "\"preferred-lifetime\": 3000,"
236         "\"rebind-timer\": 2000, "
237         "\"renew-timer\": 1000, "
238         "\"option-data\": [ {"
239         "    \"name\": \"vendor-opts\","
240         "    \"data\": \"4491\""
241         "},"
242         "{"
243         "    \"name\": \"tftp-servers\","
244         "    \"space\": \"vendor-4491\","
245         "    \"data\": \"3000:3::123\""
246         "} ],"
247         "\"subnet6\": [ "
248         " { "
249         "    \"subnet\": \"2001:db8:1::/48\", "
250         "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
251         "    \"interface\" : \"eth0\","
252         "    \"reservations\": ["
253         "    {"
254         "        \"duid\": \"01:02:03:05\","
255         "        \"ip-addresses\": [ \"2001:db8:1::2\" ],"
256         "        \"option-data\": [ {"
257         "            \"name\": \"vendor-opts\","
258         "            \"data\": \"4491\""
259         "        },"
260         "        {"
261         "            \"name\": \"tftp-servers\","
262         "            \"space\": \"vendor-4491\","
263         "            \"data\": \"3000:1::234\""
264         "        } ]"
265         "    } ]"
266         " } ]"
267     "}",
268 
269     // Configuration 6:
270     "{ "
271         "\"interfaces-config\": {"
272         "  \"interfaces\": [ \"*\" ]"
273         "},"
274         "\"host-reservation-identifiers\": [ \"duid\" ],"
275         "\"valid-lifetime\": 40, "
276         "\"preferred-lifetime\": 30,"
277         "\"rebind-timer\": 20, "
278         "\"renew-timer\": 10, "
279         "\"subnet6\": [ "
280         " { "
281         "    \"subnet\": \"2001:db8:1::/48\", "
282         "    \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::2\" } ],"
283         "    \"pd-pools\": ["
284         "        {"
285         "            \"prefix\": \"3000::\","
286         "            \"prefix-len\": 119,"
287         "            \"delegated-len\": 120"
288         "        }"
289         "    ],"
290         "    \"interface\" : \"eth0\""
291         "} ]"
292     "}",
293 
294     // Configuration 7:
295     "{ "
296         "\"interfaces-config\": {"
297         "  \"interfaces\": [ \"*\" ]"
298         "},"
299         "\"host-reservation-identifiers\": [ \"duid\" ],"
300         "\"valid-lifetime\": 40, "
301         "\"preferred-lifetime\": 30,"
302         "\"rebind-timer\": 20, "
303         "\"renew-timer\": 10, "
304         "\"subnet6\": [ "
305         " { "
306         "    \"subnet\": \"2001:db8:1::/48\", "
307         "    \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::2\" } ],"
308         "    \"pd-pools\": ["
309         "        {"
310         "            \"prefix\": \"3000::\","
311         "            \"prefix-len\": 119,"
312         "            \"delegated-len\": 120"
313         "        }"
314         "    ],"
315         "    \"interface\" : \"eth0\","
316         "    \"reservations\": ["
317         "        {"
318         "            \"duid\": \"04:03:02:01\","
319         "            \"ip-addresses\": [ \"2001:db8:1::2\" ],"
320         "            \"prefixes\": [ \"3000::100/120\" ]"
321         "        }"
322         "    ]"
323         "} ]"
324     "}",
325 
326     // Configuration 8: Global HRs TYPE_NAs
327     "{ "
328         "\"interfaces-config\": { \n"
329         "  \"interfaces\": [ \"*\" ] \n"
330         "},\n "
331         "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
332         "\"reservations\": [ \n"
333         "{ \n"
334         "   \"duid\": \"01:02:03:04\", \n"
335         "   \"hostname\": \"duid-host-fixed\", \n"
336         "   \"ip-addresses\": [ \"3001::1\" ] \n"
337         "}, \n"
338         "{ \n"
339         "   \"duid\": \"01:02:03:05\", \n"
340         "   \"hostname\": \"duid-host-dynamic\" \n"
341         "}, \n"
342         "{ \n"
343         "   \"hw-address\": \"38:60:77:d5:ff:ee\", \n"
344         "   \"hostname\": \"hw-host\" \n"
345         "} \n"
346         "], \n"
347         "\"valid-lifetime\": 4000,  \n"
348         "\"preferred-lifetime\": 3000, \n"
349         "\"rebind-timer\": 2000,  \n"
350         "\"renew-timer\": 1000,  \n"
351         "\"mac-sources\": [ \"ipv6-link-local\" ],  \n"
352         "\"subnet6\": [  \n"
353         " {  \n"
354         "    \"id\": 1, \n"
355         "    \"subnet\": \"2001:db8:1::/48\",  \n"
356         "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], \n"
357         "    \"interface\" : \"eth0\", \n"
358         "    \"reservations-global\": true, \n"
359         "    \"reservations-in-subnet\": false \n"
360         " },"
361         " {  \n"
362         "    \"id\": 2, \n"
363         "    \"subnet\": \"2001:db8:2::/48\",  \n"
364         "    \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ], \n"
365         "    \"interface\" : \"eth1\", \n"
366         "    \"reservations\": [ \n"
367         "    { \n"
368         "       \"duid\": \"01:02:03:05\", \n"
369         "       \"hostname\": \"subnet-duid-host\" \n"
370         "    }] \n"
371         " }"
372         " ] \n"
373     "} \n"
374     ,
375     // Configuration 9: Global HRs TYPE_PDs
376     "{ "
377         "\"interfaces-config\": { \n"
378         "  \"interfaces\": [ \"*\" ] \n"
379         "},\n "
380         "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
381         "\"reservations\": [ \n"
382         "{ \n"
383         "   \"duid\": \"01:02:03:04\", \n"
384         "   \"hostname\": \"duid-host-fixed\", \n"
385         "   \"prefixes\": [ \"4000::100/120\" ]"
386         "}, \n"
387         "{ \n"
388         "   \"duid\": \"01:02:03:05\", \n"
389         "   \"hostname\": \"duid-host-dynamic\" \n"
390         "} \n"
391         "], \n"
392         "\"valid-lifetime\": 4000,  \n"
393         "\"preferred-lifetime\": 3000, \n"
394         "\"rebind-timer\": 2000,  \n"
395         "\"renew-timer\": 1000,  \n"
396         "\"mac-sources\": [ \"ipv6-link-local\" ],  \n"
397         "\"subnet6\": [  \n"
398         " {  \n"
399         "    \"id\": 1, \n"
400         "    \"subnet\": \"2001:db8:1::/48\",  \n"
401         "    \"interface\" : \"eth0\", \n"
402         "    \"reservations-global\": true, \n"
403         "    \"reservations-in-subnet\": false, \n"
404         "    \"pd-pools\": [ \n"
405         "    { \n"
406         "       \"prefix\": \"3000::\", \n"
407         "       \"prefix-len\": 119, \n"
408         "       \"delegated-len\": 120 \n"
409         "    }] \n"
410         " },"
411         " {  \n"
412         "    \"id\": 2, \n"
413         "    \"subnet\": \"2001:db8:2::/48\",  \n"
414         "    \"interface\" : \"eth1\", \n"
415         "    \"pd-pools\": [ \n"
416         "    { \n"
417         "       \"prefix\": \"3001::\", \n"
418         "       \"prefix-len\": 119, \n"
419         "       \"delegated-len\": 120 \n"
420         "    }], \n"
421         "    \"reservations\": [ \n"
422         "    { \n"
423         "       \"duid\": \"01:02:03:05\", \n"
424         "       \"hostname\": \"subnet-duid-host\" \n"
425         "    }] \n"
426         " }"
427         " ] \n"
428     "} \n",
429 
430     // Configuration 10: client-class reservation in global, shared network
431     // and client-class guarded pools.
432     "{ \"interfaces-config\": {\n"
433         "      \"interfaces\": [ \"*\" ]\n"
434         "},\n"
435         "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
436         "\"client-classes\": ["
437         "{"
438         "     \"name\": \"reserved_class\""
439         "},"
440         "{"
441         "     \"name\": \"unreserved_class\","
442         "     \"test\": \"not member('reserved_class')\""
443         "}"
444         "],\n"
445         "\"reservations-global\": true,\n"
446         "\"reservations-in-subnet\": false,\n"
447         "\"valid-lifetime\": 4000,\n"
448         "\"reservations\": [ \n"
449         "{\n"
450         "   \"duid\": \"01:02:03:05\",\n"
451         "   \"client-classes\": [ \"reserved_class\" ]\n"
452         "}\n"
453         "],\n"
454         "\"shared-networks\": [{"
455         "    \"name\": \"frog\",\n"
456         "    \"subnet6\": [\n"
457         "        {\n"
458         "            \"subnet\": \"2001:db8:1::/64\", \n"
459         "            \"id\": 10,"
460         "            \"pools\": ["
461         "                {"
462         "                    \"pool\": \"2001:db8:1::10-2001:db8:1::11\","
463         "                    \"client-class\": \"reserved_class\""
464         "                }"
465         "            ],\n"
466         "            \"interface\": \"eth0\"\n"
467         "        },\n"
468         "        {\n"
469         "            \"subnet\": \"2001:db8:2::/64\", \n"
470         "            \"id\": 11,"
471         "            \"pools\": ["
472         "                {"
473         "                    \"pool\": \"2001:db8:2::10-2001:db8:2::11\","
474         "                    \"client-class\": \"unreserved_class\""
475         "                }"
476         "            ],\n"
477         "            \"interface\": \"eth0\"\n"
478         "        }\n"
479         "    ]\n"
480         "}]\n"
481     "}",
482 
483     // Configuration 11: client-class reservation in global, shared network
484     // and client-class guarded subnets.
485     "{ \"interfaces-config\": {\n"
486         "      \"interfaces\": [ \"*\" ]\n"
487         "},\n"
488         "\"host-reservation-identifiers\": [ \"duid\", \"hw-address\" ], \n"
489         "\"client-classes\": ["
490         "{"
491         "     \"name\": \"reserved_class\""
492         "},"
493         "{"
494         "     \"name\": \"unreserved_class\","
495         "     \"test\": \"not member('reserved_class')\""
496         "}"
497         "],\n"
498         "\"reservations-global\": true,\n"
499         "\"reservations-in-subnet\": false,\n"
500         "\"valid-lifetime\": 4000,\n"
501         "\"reservations\": [ \n"
502         "{\n"
503         "   \"duid\": \"01:02:03:05\",\n"
504         "   \"client-classes\": [ \"reserved_class\" ]\n"
505         "}\n"
506         "],\n"
507         "\"shared-networks\": [{"
508         "    \"name\": \"frog\",\n"
509         "    \"subnet6\": [\n"
510         "        {\n"
511         "            \"subnet\": \"2001:db8:1::/64\", \n"
512         "            \"client-class\": \"reserved_class\","
513         "            \"id\": 10,"
514         "            \"pools\": ["
515         "                {"
516         "                    \"pool\": \"2001:db8:1::10-2001:db8:1::11\""
517         "                }"
518         "            ],\n"
519         "            \"interface\": \"eth0\"\n"
520         "        },\n"
521         "        {\n"
522         "            \"subnet\": \"2001:db8:2::/64\", \n"
523         "            \"client-class\": \"unreserved_class\","
524         "            \"id\": 11,"
525         "            \"pools\": ["
526         "                {"
527         "                    \"pool\": \"2001:db8:2::10-2001:db8:2::11\""
528         "                }"
529         "            ],\n"
530         "            \"interface\": \"eth0\"\n"
531         "        }\n"
532         "    ]\n"
533         "}]\n"
534     "}",
535 
536     // Configuration 12 client-class reservation and client-class guarded pools.
537     "{ \"interfaces-config\": {\n"
538         "      \"interfaces\": [ \"*\" ]\n"
539         "},\n"
540         "\"client-classes\": ["
541         "{"
542         "     \"name\": \"reserved_class\""
543         "},"
544         "{"
545         "     \"name\": \"unreserved_class\","
546         "     \"test\": \"not member('reserved_class')\""
547         "}"
548         "],\n"
549         "\"valid-lifetime\": 4000,\n"
550         "\"subnet6\": [\n"
551         "    {\n"
552         "        \"subnet\": \"2001:db8:1::/64\", \n"
553         "        \"id\": 10,"
554         "        \"reservations\": [{ \n"
555         "            \"duid\": \"01:02:03:05\",\n"
556         "            \"client-classes\": [ \"reserved_class\" ]\n"
557         "        }],\n"
558         "        \"pools\": ["
559         "            {"
560         "                \"pool\": \"2001:db8:1::10-2001:db8:1::11\","
561         "                \"client-class\": \"reserved_class\""
562         "            },"
563         "            {"
564         "                \"pool\": \"2001:db8:1::20-2001:db8:1::21\","
565         "                \"client-class\": \"unreserved_class\""
566         "            }"
567         "        ],\n"
568         "        \"interface\": \"eth0\"\n"
569         "    }\n"
570         "]\n"
571     "}",
572 
573     // Configuration 13 multiple reservations for the same IP address.
574     "{ \"interfaces-config\": {\n"
575         "      \"interfaces\": [ \"*\" ]\n"
576         "},\n"
577         "\"valid-lifetime\": 4000,\n"
578         "\"ip-reservations-unique\": false,\n"
579         "\"subnet6\": [\n"
580         "    {\n"
581         "        \"subnet\": \"2001:db8:1::/64\",\n"
582         "        \"id\": 10,"
583         "        \"reservations\": [\n"
584         "            {\n"
585         "                \"duid\": \"01:02:03:04\",\n"
586         "                \"ip-addresses\": [ \"2001:db8:1::15\" ]\n"
587         "            },\n"
588         "            {\n"
589         "                \"duid\": \"01:02:03:05\",\n"
590         "                \"ip-addresses\": [ \"2001:db8:1::15\" ]\n"
591         "            }\n"
592         "        ],\n"
593         "        \"pools\": ["
594         "            {\n"
595         "                \"pool\": \"2001:db8:1::10-2001:db8:1::200\""
596         "            }\n"
597         "        ],\n"
598         "        \"interface\": \"eth0\"\n"
599         "    }\n"
600         "]\n"
601     "}",
602 
603     // Configuration 14 multiple reservations for the same delegated prefix.
604     "{ \"interfaces-config\": {\n"
605         "      \"interfaces\": [ \"*\" ]\n"
606         "},\n"
607         "\"valid-lifetime\": 4000,\n"
608         "\"ip-reservations-unique\": false,\n"
609         "\"subnet6\": [\n"
610         "    {\n"
611         "        \"subnet\": \"2001:db8:1::/64\",\n"
612         "        \"id\": 10,"
613         "        \"reservations\": [\n"
614         "            {\n"
615         "                \"duid\": \"01:02:03:04\",\n"
616         "                \"prefixes\": [ \"3000::5a:0/112\" ]\n"
617         "            },\n"
618         "            {\n"
619         "                \"duid\": \"01:02:03:05\",\n"
620         "                \"prefixes\": [ \"3000::5a:0/112\" ]\n"
621         "            }\n"
622         "        ],\n"
623         "        \"pd-pools\": ["
624         "            {\n"
625         "                \"prefix\": \"3000::\",\n"
626         "                \"prefix-len\": 64,\n"
627         "                \"delegated-len\": 112\n"
628         "            }\n"
629         "        ],\n"
630         "        \"interface\": \"eth0\"\n"
631         "    }\n"
632         "]\n"
633     "}"
634 };
635 
636 /// @brief Base class representing leases and hints conveyed within IAs.
637 ///
638 /// This is a base class for @ref Reservation and @ref Hint classes.
639 class IAResource {
640 public:
641 
642     /// @brief Constructor.
643     ///
644     /// Creates a resource instance from a string. The string is provided in
645     /// one of the following formats:
646     /// - "2001:db8:1::1" for addresses.
647     /// - "2001:db8::/64" for prefixes.
648     /// - "::/0" to mark lease or hint as unspecified (empty).
649     IAResource(const std::string& resource);
650 
651     /// @brief Checks if resource is unspecified.
652     ///
653     /// @return true if resource is unspecified.
654     bool isEmpty() const;
655 
656     /// @brief Checks if resource is a prefix.
657     ///
658     /// @return true if resource is a prefix.
659     bool isPrefix() const;
660 
661     /// @brief Returns prefix or address (depending on resource type).
662     const IOAddress& getPrefix() const;
663 
664     /// @brief Returns prefix length.
665     uint8_t getPrefixLen() const;
666 
667     /// @brief Returns textual representation of the resource.
668     std::string toText() const;
669 
670     /// @brief Operator converting resource to string.
671     operator std::string() const;
672 
673 private:
674 
675     /// @brief Holds prefix or address (depending on resource type).
676     IOAddress prefix_;
677 
678     /// @brief Holds prefix length (for prefixes).
679     uint8_t prefix_len_;
680 
681 };
682 
IAResource(const std::string & resource)683 IAResource::IAResource(const std::string& resource)
684     : prefix_(IOAddress::IPV6_ZERO_ADDRESS()), prefix_len_(0) {
685     // Check if resource is a prefix, i.e. search for slash.
686     size_t slash_pos = resource.find("/");
687     if ((slash_pos != std::string::npos) && (slash_pos < resource.size() - 1)) {
688         prefix_len_ = boost::lexical_cast<unsigned int>(resource.substr(slash_pos + 1));
689     }
690     prefix_ = IOAddress(resource.substr(0, slash_pos));
691 }
692 
693 bool
isEmpty() const694 IAResource::isEmpty() const {
695     return (prefix_.isV6Zero() && (prefix_len_ == 0));
696 }
697 
698 bool
isPrefix() const699 IAResource::isPrefix() const {
700     return (!isEmpty() && (prefix_len_ > 0));
701 }
702 
703 const IOAddress&
getPrefix() const704 IAResource::getPrefix() const {
705     return (prefix_);
706 }
707 
708 uint8_t
getPrefixLen() const709 IAResource::getPrefixLen() const {
710     return (prefix_len_);
711 }
712 
713 std::string
toText() const714 IAResource::toText() const {
715     std::ostringstream s;
716     s << "\"" << prefix_;
717     if (prefix_len_ > 0) {
718         s << "/" << static_cast<int>(prefix_len_);
719     }
720     s << "\"";
721     return (s.str());
722 }
723 
operator std::string() const724 IAResource::operator std::string() const {
725     return (toText());
726 }
727 
728 /// @brief Address or prefix reservation.
729 class Reservation : public IAResource {
730 public:
731 
732     /// @brief Constructor
733     ///
734     /// @param resource Resource string as for @ref IAResource constructor.
Reservation(const std::string & resource)735     Reservation(const std::string& resource)
736         : IAResource(resource) {
737     }
738 
739     /// @brief Convenience function returning unspecified resource.
740     static const Reservation& UNSPEC();
741 
742 };
743 
UNSPEC()744 const Reservation& Reservation::UNSPEC() {
745     static Reservation unspec("::/0");
746     return (unspec);
747 }
748 
749 /// @brief Address or prefix hint.
750 class Hint : public IAResource {
751 public:
752 
753     /// @brief Constructor.
754     ///
755     /// Includes IAID of an IA in which hint should be placed.
756     ///
757     /// @param iaid IAID of IA in which hint should be placed.
758     /// @param resource Resource string as for @ref IAResource constructor.
Hint(const IAID & iaid,const std::string & resource)759     Hint(const IAID& iaid, const std::string& resource)
760         : IAResource(resource), iaid_(iaid) {
761     }
762 
763     /// @brief Returns IAID.
764     const IAID& getIAID() const;
765 
766     /// @brief Convenience function returning unspecified hint.
767     static const Hint& UNSPEC();
768 
769 private:
770 
771     /// @brief Holds IAID as 32-bit unsigned integer.
772     IAID iaid_;
773 };
774 
775 const IAID&
getIAID() const776 Hint::getIAID() const {
777     return (iaid_);
778 }
779 
UNSPEC()780 const Hint& Hint::UNSPEC() {
781     static Hint unspec(IAID(0), "::/0");
782     return (unspec);
783 }
784 
785 /// @brief Test fixture class for testing host reservations
786 class HostTest : public Dhcpv6SrvTest {
787 public:
788 
789 
790     /// @brief Constructor.
791     ///
792     /// Sets up fake interfaces.
HostTest()793     HostTest()
794         : Dhcpv6SrvTest(),
795           iface_mgr_test_config_(true),
796           client_(),
797           do_solicit_(std::bind(&Dhcp6Client::doSolicit, &client_, true)),
798           do_solicit_request_(std::bind(&Dhcp6Client::doSARR, &client_)) {
799     }
800 
801     /// @brief Checks that specified option contains a desired address.
802     ///
803     /// The option must cast to the @ref Option6AddrLst type. The function
804     /// expects that this option contains at least one address and checks
805     /// first address for equality with @ref expected_addr.
806     ///
807     /// @param option_type Option type.
808     /// @param expected_addr Desired address.
809     /// @param config Configuration obtained from the server.
verifyAddressOption(const uint16_t option_type,const std::string & expected_addr,const Dhcp6Client::Configuration & config) const810     void verifyAddressOption(const uint16_t option_type,
811                              const std::string& expected_addr,
812                              const Dhcp6Client::Configuration& config) const {
813         Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
814             Option6AddrLst>(config.findOption(option_type));
815         ASSERT_TRUE(opt) << "option " << option_type << " not found or it "
816             "is of incorrect type";
817         Option6AddrLst::AddressContainer addrs = opt->getAddresses();
818         ASSERT_GE(addrs.size(), 1) << "test failed for option type " << option_type;
819         EXPECT_EQ(expected_addr, addrs[0].toText())
820             << "test failed for option type " << option_type;
821     }
822 
823     /// @brief Verifies that the reservation is retrieved by the server
824     /// using one of the host identifiers.
825     ///
826     /// @param client Reference to a client to be used in the test.
827     /// The client should be preconfigured to insert a specific identifier
828     /// into the message, e.g. DUID, HW address etc.
829     /// @param config_index Index of the configuration to use in the CONFIGS
830     /// table.
831     /// @param exp_ip_address Expected IPv6 address in the returned
832     /// reservation.
testReservationByIdentifier(Dhcp6Client & client,const unsigned int config_index,const std::string & exp_ip_address)833     void testReservationByIdentifier(Dhcp6Client& client,
834                                      const unsigned int config_index,
835                                      const std::string& exp_ip_address) {
836         configure(CONFIGS[config_index], *client.getServer());
837 
838         const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
839             getCfgSubnets6()->getAll();
840         ASSERT_EQ(1, subnets->size());
841 
842         // Configure client to request IA_NA and append IA_NA option
843         //  to the client's message.
844         client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
845 
846         // Perform 4-way exchange.
847         ASSERT_NO_THROW(client.doSARR());
848 
849         // Verify that the client we got the reserved address
850         ASSERT_EQ(1, client.getLeaseNum());
851         Lease6 lease_client = client.getLease(0);
852         EXPECT_EQ(exp_ip_address, lease_client.addr_.toText());
853     }
854 
855     /// @brief Initiate exchange with DHCPv6 server.
856     ///
857     /// This method initiates DHCPv6 message exchange between a specified
858     /// client and the server. The msg_type is used to indicate what kind
859     /// of exchange should be initiated. If the message type is a Renew
860     /// or Rebind, the 4-way handshake is made first. If the message type
861     /// is a Request, the Solicit-Advertise is done prior to this.
862     ///
863     /// @param msg_type Message type to be sent to the server.
864     /// @param client Reference to a client to be used to initiate the
865     /// exchange with the server.
866     void doExchange(const uint16_t msg_type, Dhcp6Client& client);
867 
868     /// @brief Verifies that host specific options override subnet specific
869     /// options.
870     ///
871     /// Overridden options are requested with Option Request option.
872     ///
873     /// @param msg_type DHCPv6 message type to be sent to the server. If the
874     /// message type is Renew or Rebind, the 4-way exchange is made prior to
875     /// sending a Renew or Rebind. For a Request case, the Solicit-Advertise
876     /// is also performed.
877     void testOverrideRequestedOptions(const uint16_t msg_type);
878 
879     /// @brief Verifies that client receives options when they are solely
880     /// defined in the host scope (and not in the global, subnet or pool
881     /// scope).
882     ///
883     /// @param msg_type DHCPv6 message type to be sent to the server. If the
884     /// message type is Renew or Rebind, the 4-way exchange is made prior to
885     /// sending a Renew or Rebind. For a Request case, the Solicit-Advertise
886     /// is also performed.
887     void testHostOnlyOptions(const uint16_t msg_type);
888 
889     /// @brief Verifies that host specific vendor options override vendor
890     /// options defined in the global scope.
891     ///
892     /// @param msg_type DHCPv6 message type to be sent to the server. If the
893     /// message type is Renew or Rebind, the 4-way exchange is made prior to
894     /// sending a Renew or Rebind. For a Request case, the Solicit-Advertise
895     /// is also performed.
896     void testOverrideVendorOptions(const uint16_t msg_type);
897 
898     /// @brief Checks if the client obtained lease for specified reservation.
899     ///
900     /// @param r Reservation.
901     /// @param [out] address_count This value is incremented if the client
902     /// obtained the address lease.
903     /// @param [out] prefix_count This value is incremented if the client
904     /// obtained the prefix lease.
905     void testLeaseForIA(const Reservation& r, size_t& address_count,
906                         size_t& prefix_count);
907 
908     /// @brief Checks if the client obtained lease for specified hint.
909     ///
910     /// The hint belongs to a specific IA (identified by IAID) and is expected
911     /// to be returned in this IA by the server.
912     ///
913     /// @param h Hint.
914     void testLeaseForIA(const Hint& h);
915 
916     /// @brief A generic test for assigning multiple reservations to a single
917     /// client sending multiple IAs.
918     ///
919     /// This test creates a server configuration which includes one subnet,
920     /// address pool of "2001:db8:1::1 - 2001:db8:1::10" and the prefix pool
921     /// of 3001::/32, with delegated prefix length of 64. The configuration
922     /// may include between 0 and 6 reservations for a client with DUID of
923     /// "01:02:03:04".
924     ///
925     /// The test performs an exchange with a server, typically 4-way exchange
926     /// or Solicit-Advertise. The client's message includes 3 IA_NAs (with
927     /// IAIDs in range of 1..3) and 3 IA_PDs (with IAIDs in range of 4..6).
928     ///
929     /// It is possible to specify hints for selected IAs. The IA is in such
930     /// case identified by the IAID.
931     ///
932     /// The test expects that the server returns 6 leases. It checks if those
933     /// leases contain all reserved addresses and prefixes specified as
934     /// arguments of the test. If the number of IAs is greater than the
935     /// number of reservations it checks that for the remaining IAs the
936     /// leases from dynamic pools are assigned.
937     ///
938     /// The strict_iaid_check flag controls whether the test should verify
939     /// that the address or prefix specified as a hint is assigned by the
940     /// server to the IA in which the hint was placed by the client.
941     ///
942     /// @param client_operation Dhcp6Client function to be executed to
943     /// perform an exchange with the server.
944     /// @param r1 Reservation 1. Default value is "unspecified", in which
945     /// case the reservation will not be created.
946     /// @param r2 Reservation 2.
947     /// @param r3 Reservation 3.
948     /// @param r4 Reservation 4.
949     /// @param r5 Reservation 5.
950     /// @param r6 Reservation 6.
951     /// @param strict_iaid_check Indicates if the test should check if the
952     /// hints sent by the client have been allocated by the server to the
953     /// particular IAs. Default value is NO (no checks).
954     /// @param h1 Hint 1. Default value is "unspecified", in which case the
955     /// hint will not be included.
956     /// @param h2 Hint 2.
957     /// @param h3 Hint 3.
958     /// @param h4 Hint 4.
959     /// @param h5 Hint 5.
960     /// @param h6 Hint 6.
961     void testMultipleIAs(const std::function<void ()>& client_operation,
962                          const Reservation& r1 = Reservation::UNSPEC(),
963                          const Reservation& r2 = Reservation::UNSPEC(),
964                          const Reservation& r3 = Reservation::UNSPEC(),
965                          const Reservation& r4 = Reservation::UNSPEC(),
966                          const Reservation& r5 = Reservation::UNSPEC(),
967                          const Reservation& r6 = Reservation::UNSPEC(),
968                          const StrictIAIDChecking& strict_iaid_check =
969                          StrictIAIDChecking::NO(),
970                          const Hint& h1 = Hint::UNSPEC(),
971                          const Hint& h2 = Hint::UNSPEC(),
972                          const Hint& h3 = Hint::UNSPEC(),
973                          const Hint& h4 = Hint::UNSPEC(),
974                          const Hint& h5 = Hint::UNSPEC(),
975                          const Hint& h6 = Hint::UNSPEC());
976 
977     /// @brief Checks if specified reservation is for address or prefix and
978     /// stores reservation in the textual format on one of the lists.
979     ///
980     /// @param [out] address_list Reference to a list containing address
981     /// reservations.
982     /// @param [out] prefix_list Reference to a list containing prefix
983     /// reservations.
984     static void storeReservation(const Reservation& r,
985                                  std::list<std::string>& address_list,
986                                  std::list<std::string>& prefix_list);
987 
988     /// @brief Creates configuration for testing processing multiple IAs.
989     ///
990     /// This method creates a server configuration which includes one subnet,
991     /// address pool of "2001:db8:1::1 - 2001:db8:1::10" and the prefix pool
992     /// of 3001::/32, with delegated prefix length of 64. The configuration
993     /// may include between 0 and 6 reservations for a client with DUID of
994     /// "01:02:03:04".
995     ///
996     /// @param r1 Reservation 1. Default value is "unspecified" in which case
997     /// the reservation will not be included in the configuration.
998     /// @param r2 Reservation 2.
999     /// @param r3 Reservation 3.
1000     /// @param r4 Reservation 4.
1001     /// @param r5 Reservation 5.
1002     /// @param r6 Reservation 6.
1003     ///
1004     /// @return Text containing server configuration in JSON format.
1005     std::string configString(const DUID& duid,
1006                              const Reservation& r1 = Reservation::UNSPEC(),
1007                              const Reservation& r2 = Reservation::UNSPEC(),
1008                              const Reservation& r3 = Reservation::UNSPEC(),
1009                              const Reservation& r4 = Reservation::UNSPEC(),
1010                              const Reservation& r5 = Reservation::UNSPEC(),
1011                              const Reservation& r6 = Reservation::UNSPEC()) const;
1012 
1013     /// @brief Verifies that an SARR exchange results in the expected lease
1014     ///
1015     /// @param client Client configured to request a single lease
1016     /// @param exp_address expected address/prefix of the lease
1017     /// @param exp_hostname expected hostname on the lease
1018     void sarrTest(Dhcp6Client& client, const std::string& exp_address,
1019                   const std::string& exp_hostname);
1020 
1021     /// @brief Configures client to include hint.
1022     ///
1023     /// @param client Reference to a client.
1024     /// @param hint Const reference to an object holding the hint.
1025     static void requestIA(Dhcp6Client& client, const Hint& hint);
1026 
1027     /// @brief Test pool or subnet selection using global class reservation.
1028     ///
1029     /// Verifies that client class specified in the global reservation
1030     /// may be used to influence pool or subnet selection.
1031     ///
1032     /// @param config_idx Index of the server configuration from the
1033     /// @c CONFIGS array.
1034     /// @param first_address Address to be allocated from the pool having
1035     /// a reservation.
1036     /// @param second_address Address to be allocated from the pool not
1037     /// having a reservation.
1038     void testGlobalClassSubnetPoolSelection(const int config_idx,
1039                                             const std::string& first_address = "2001:db8:1::10",
1040                                             const std::string& second_address = "2001:db8:2::10");
1041 
1042     /// @brief Test that two clients having reservations for the same IP
1043     /// address are offered the reserved lease.
1044     ///
1045     /// This test verifies the case when two clients have reservations for
1046     /// the same IP address. The first client sends Solicit and is offered
1047     /// the reserved address. At the same time, the second client having
1048     /// the reservation for the same IP address performs 4-way exchange
1049     /// using the reserved address as a hint in Solicit.
1050     /// The client gets the lease for this address. This test verifies
1051     /// that the allocation engine correctly identifies that the second
1052     /// client has a reservation for this address.
1053     ///
1054     /// @param duid1 Hardware address of the first client having the
1055     /// reservation.
1056     /// @param duid2 Hardware address of the second client having the
1057     /// reservation.
1058     void testMultipleClientsRace(const std::string& duid1,
1059                                  const std::string& duid2);
1060 
1061     /// @brief Configures client to include 6 IAs without hints.
1062     ///
1063     /// This method configures the client to include 3 IA_NAs and
1064     /// 3 IA_PDs.
1065     ///
1066     /// @param client Reference to a client.
1067     static void requestEmptyIAs(Dhcp6Client& client);
1068 
1069     /// @brief Interface Manager's fake configuration control.
1070     IfaceMgrTestConfig iface_mgr_test_config_;
1071 
1072     /// @brief Instance of the common DHCPv6 client.
1073     Dhcp6Client client_;
1074 
1075     /// @brief Pointer to the Dhcp6Client::doSolicit method.
1076     std::function<void() > do_solicit_;
1077 
1078     /// @brief Pointer to the Dhcp6Client::doSARR method.
1079     std::function<void() > do_solicit_request_;
1080 };
1081 
1082 void
doExchange(const uint16_t msg_type,Dhcp6Client & client)1083 HostTest::doExchange(const uint16_t msg_type, Dhcp6Client& client) {
1084     switch (msg_type) {
1085     case DHCPV6_INFORMATION_REQUEST:
1086         ASSERT_NO_THROW(client.doInfRequest());
1087         break;
1088     case DHCPV6_REQUEST:
1089         ASSERT_NO_THROW(client.doSARR());
1090         break;
1091     case DHCPV6_SOLICIT:
1092         ASSERT_NO_THROW(client.doSolicit());
1093         break;
1094     case DHCPV6_RENEW:
1095         ASSERT_NO_THROW(client.doSARR());
1096         ASSERT_NO_THROW(client.doRenew());
1097         break;
1098     case DHCPV6_REBIND:
1099         ASSERT_NO_THROW(client.doSARR());
1100         ASSERT_NO_THROW(client.doRebind());
1101         break;
1102     default:
1103         ;
1104     }
1105 
1106     // Make sure that the server has responded with a Reply.
1107     ASSERT_TRUE(client.getContext().response_);
1108     ASSERT_EQ(DHCPV6_REPLY, client.getContext().response_->getType());
1109 
1110 }
1111 
1112 
1113 void
testOverrideRequestedOptions(const uint16_t msg_type)1114 HostTest::testOverrideRequestedOptions(const uint16_t msg_type) {
1115     Dhcp6Client client;
1116     // Reservation has been made for a client with this DUID.
1117     client.setDUID("01:02:03:05");
1118 
1119     // Request all options specified in the configuration.
1120     client.requestOption(D6O_NAME_SERVERS);
1121     client.requestOption(D6O_NIS_SERVERS);
1122     client.requestOption(D6O_NISP_SERVERS);
1123     client.requestOption(D6O_SNTP_SERVERS);
1124 
1125     configure(CONFIGS[3], *client.getServer());
1126 
1127     ASSERT_NO_FATAL_FAILURE(doExchange(msg_type, client));
1128 
1129     {
1130         SCOPED_TRACE("host specific dns-servers");
1131         // Host specific DNS server should be used.
1132         verifyAddressOption(D6O_NAME_SERVERS, "3000:1::234", client.config_);
1133     }
1134 
1135     {
1136         SCOPED_TRACE("host specific nis-servers");
1137         // Host specific NIS server should be used.
1138         verifyAddressOption(D6O_NIS_SERVERS, "3000:1::234", client.config_);
1139     }
1140 
1141     {
1142         SCOPED_TRACE("subnet specific sntp-servers");
1143         // Subnet specific SNTP server should be used as it is not specified
1144         // in a host scope.
1145         verifyAddressOption(D6O_SNTP_SERVERS, "3000:2::123", client.config_);
1146     }
1147 
1148     {
1149         SCOPED_TRACE("global nisp-servers");
1150         // Globally specified NISP server should be used as it is not
1151         // specified in a host scope.
1152         verifyAddressOption(D6O_NISP_SERVERS, "3000:3::123", client.config_);
1153     }
1154 }
1155 
1156 void
testLeaseForIA(const Reservation & r,size_t & address_count,size_t & prefix_count)1157 HostTest::testLeaseForIA(const Reservation& r, size_t& address_count,
1158                          size_t& prefix_count) {
1159     if (r.isPrefix()) {
1160         ++prefix_count;
1161         EXPECT_TRUE(client_.hasLeaseForPrefix(r.getPrefix(),
1162                                               r.getPrefixLen(),
1163                                               IAID(3 + prefix_count)));
1164 
1165     } else if (!r.isEmpty()) {
1166         ++address_count;
1167         EXPECT_TRUE(client_.hasLeaseForAddress(r.getPrefix(),
1168                                                IAID(address_count)));
1169     }
1170 }
1171 
1172 void
testLeaseForIA(const Hint & h)1173 HostTest::testLeaseForIA(const Hint& h) {
1174     if (h.isPrefix()) {
1175         EXPECT_TRUE(client_.hasLeaseForPrefix(h.getPrefix(), h.getPrefixLen(),
1176                                               h.getIAID()))
1177             << "there is no lease for prefix " << h.toText()
1178             << " and IAID = " << h.getIAID();
1179 
1180     } else if (!h.isEmpty()) {
1181         EXPECT_TRUE(client_.hasLeaseForAddress(h.getPrefix(), h.getIAID()))
1182             << "there is no lease for address " << h.toText()
1183             << " and IAID = " << h.getIAID();
1184     }
1185 }
1186 
1187 void
testMultipleIAs(const std::function<void ()> & client_operation,const Reservation & r1,const Reservation & r2,const Reservation & r3,const Reservation & r4,const Reservation & r5,const Reservation & r6,const StrictIAIDChecking & strict_iaid_check,const Hint & h1,const Hint & h2,const Hint & h3,const Hint & h4,const Hint & h5,const Hint & h6)1188 HostTest::testMultipleIAs(const std::function<void ()>& client_operation,
1189                           const Reservation& r1, const Reservation& r2,
1190                           const Reservation& r3, const Reservation& r4,
1191                           const Reservation& r5, const Reservation& r6,
1192                           const StrictIAIDChecking& strict_iaid_check,
1193                           const Hint& h1, const Hint& h2 ,
1194                           const Hint& h3, const Hint& h4,
1195                           const Hint& h5, const Hint& h6) {
1196     client_.setDUID("01:02:03:04");
1197 
1198     /// Create configuration with 0 to 6 reservations.
1199     const std::string c = configString(*client_.getDuid(), r1, r2, r3,
1200                                        r4, r5, r6);
1201 
1202     ASSERT_NO_THROW(configure(c, *client_.getServer()));
1203 
1204     // First includes all IAs. They are initially empty.
1205     requestEmptyIAs(client_);
1206 
1207     // For each specified hint, include it in the respective IA. Hints
1208     // which are "unspecified" will not be included.
1209     requestIA(client_, h1);
1210     requestIA(client_, h2);
1211     requestIA(client_, h3);
1212     requestIA(client_, h4);
1213     requestIA(client_, h5);
1214     requestIA(client_, h6);
1215 
1216 
1217     // Send Solicit and require that the client saves received configuration
1218     // so as we can test that advertised configuration is correct.
1219     ASSERT_NO_THROW(client_operation());
1220 
1221     ASSERT_EQ(6, client_.getLeaseNum());
1222 
1223     // Count reserved addresses and prefixes assigned from reservations.
1224     size_t address_count = 0;
1225     size_t prefix_count = 0;
1226 
1227     testLeaseForIA(r1, address_count, prefix_count);
1228     testLeaseForIA(r2, address_count, prefix_count);
1229     testLeaseForIA(r3, address_count, prefix_count);
1230     testLeaseForIA(r4, address_count, prefix_count);
1231     testLeaseForIA(r5, address_count, prefix_count);
1232     testLeaseForIA(r6, address_count, prefix_count);
1233 
1234     // Get all addresses assigned from the dynamic pool (not reserved).
1235     std::vector<Lease6> leases =
1236         client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
1237                                         IOAddress("2001:db8:1::10"));
1238     // There are 3 IA_NAs and for a few we have assigned reserved addresses.
1239     // The remaining ones should be assigned from the dynamic pool.
1240     ASSERT_EQ(3 - address_count, leases.size());
1241 
1242     // Get all prefixes assigned from the dynamic pool (not reserved).
1243     leases =  client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
1244     ASSERT_EQ(3 - prefix_count, leases.size());
1245 
1246     // Check that the hints have been allocated to respective IAs.
1247     if (strict_iaid_check) {
1248         testLeaseForIA(h1);
1249         testLeaseForIA(h2);
1250         testLeaseForIA(h3);
1251         testLeaseForIA(h4);
1252         testLeaseForIA(h5);
1253         testLeaseForIA(h6);
1254     }
1255 }
1256 
1257 
1258 void
storeReservation(const Reservation & r,std::list<std::string> & address_list,std::list<std::string> & prefix_list)1259 HostTest::storeReservation(const Reservation& r,
1260                            std::list<std::string>& address_list,
1261                            std::list<std::string>& prefix_list) {
1262     if (!r.isEmpty()) {
1263         if (r.isPrefix()) {
1264             prefix_list.push_back(r);
1265         } else {
1266             address_list.push_back(r);
1267         }
1268     }
1269 }
1270 
1271 std::string
configString(const DUID & duid,const Reservation & r1,const Reservation & r2,const Reservation & r3,const Reservation & r4,const Reservation & r5,const Reservation & r6) const1272 HostTest::configString(const DUID& duid,
1273                        const Reservation& r1, const Reservation& r2,
1274                        const Reservation& r3, const Reservation& r4,
1275                        const Reservation& r5, const Reservation& r6) const {
1276     std::list<std::string> address_list;
1277     std::list<std::string> prefix_list;
1278     storeReservation(r1, address_list, prefix_list);
1279     storeReservation(r2, address_list, prefix_list);
1280     storeReservation(r3, address_list, prefix_list);
1281     storeReservation(r4, address_list, prefix_list);
1282     storeReservation(r5, address_list, prefix_list);
1283     storeReservation(r6, address_list, prefix_list);
1284 
1285     std::ostringstream s;
1286     s << "{ "
1287         "\"interfaces-config\": {"
1288         "  \"interfaces\": [ \"*\" ]"
1289         "},"
1290         "\"valid-lifetime\": 4000, "
1291         "\"preferred-lifetime\": 3000,"
1292         "\"rebind-timer\": 2000, "
1293         "\"renew-timer\": 1000, "
1294         "\"subnet6\": [ "
1295         " { "
1296         "    \"subnet\": \"2001:db8:1::/48\", "
1297         "    \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::10\" } ],"
1298         "    \"pd-pools\": [ { \"prefix\": \"3001::\", \"prefix-len\": 32,"
1299         "                      \"delegated-len\": 64 } ],"
1300         "    \"interface\" : \"eth0\"";
1301 
1302     // Create reservations.
1303     if (!address_list.empty() || !prefix_list.empty()) {
1304         s << ","
1305             "    \"reservations\": ["
1306             "    {"
1307             "        \"duid\": ";
1308         s << "\"" << duid.toText() << "\",";
1309 
1310         if (!address_list.empty()) {
1311             s << "        \"ip-addresses\": [ "
1312               << boost::algorithm::join(address_list, ", ")
1313               << "]";
1314         }
1315 
1316         if (!prefix_list.empty()) {
1317             if (!address_list.empty()) {
1318                 s << ", ";
1319             }
1320             s << "        \"prefixes\": [ "
1321               << boost::algorithm::join(prefix_list, ", ")
1322               << "]";
1323         }
1324 
1325         s <<  "    } ]";
1326     }
1327 
1328     s << " } ]"
1329          "}";
1330 
1331     return (s.str());
1332 }
1333 
1334 void
requestIA(Dhcp6Client & client,const Hint & hint)1335 HostTest::requestIA(Dhcp6Client& client, const Hint& hint) {
1336     if ((hint.getIAID() != 0) && !hint.isEmpty()) {
1337         if (hint.isPrefix()) {
1338             client.requestPrefix(hint.getIAID(), hint.getPrefixLen(),
1339                                  hint.getPrefix());
1340         } else {
1341             client.requestAddress(hint.getIAID(), hint.getPrefix());
1342         }
1343     }
1344 }
1345 
1346 void
testHostOnlyOptions(const uint16_t msg_type)1347 HostTest::testHostOnlyOptions(const uint16_t msg_type) {
1348     Dhcp6Client client;
1349     client.setDUID("01:02:03:05");
1350     client.requestOption(D6O_NAME_SERVERS);
1351     client.requestOption(D6O_NIS_SERVERS);
1352 
1353     configure(CONFIGS[3], *client.getServer());
1354 
1355     ASSERT_NO_FATAL_FAILURE(doExchange(msg_type, client));
1356 
1357     {
1358         SCOPED_TRACE("host specific dns-servers");
1359         // DNS servers are specified only in a host scope.
1360         verifyAddressOption(D6O_NAME_SERVERS, "3000:1::234", client.config_);
1361     }
1362 
1363     {
1364         SCOPED_TRACE("host specific nis-servers");
1365         // NIS servers are specified only in a host scope.
1366         verifyAddressOption(D6O_NIS_SERVERS, "3000:1::234", client.config_);
1367     }
1368 }
1369 
1370 void
testOverrideVendorOptions(const uint16_t msg_type)1371 HostTest::testOverrideVendorOptions(const uint16_t msg_type) {
1372     Dhcp6Client client;
1373     client.setDUID("01:02:03:05");
1374 
1375     // Client needs to include Vendor Specific Information option
1376     // with ORO suboption, which the server will use to determine
1377     // which suboptions should be returned to the client.
1378     OptionVendorPtr opt_vendor(new OptionVendor(Option::V6,
1379                                                 VENDOR_ID_CABLE_LABS));
1380     // Include ORO with TFTP servers suboption code being requested.
1381     opt_vendor->addOption(OptionPtr(new OptionUint16(Option::V6, DOCSIS3_V6_ORO,
1382                                                      DOCSIS3_V6_TFTP_SERVERS)));
1383     client.addExtraOption(opt_vendor);
1384 
1385     configure(CONFIGS[5], *client.getServer());
1386 
1387     ASSERT_NO_FATAL_FAILURE(doExchange(msg_type, client));
1388 
1389     // Vendor Specific Information option should be returned by the server.
1390     OptionVendorPtr vendor_opt = boost::dynamic_pointer_cast<
1391         OptionVendor>(client.config_.findOption(D6O_VENDOR_OPTS));
1392     ASSERT_TRUE(vendor_opt);
1393 
1394     // TFTP server suboption should be returned because it was requested
1395     // with Option Request suboption.
1396     Option6AddrLstPtr tftp = boost::dynamic_pointer_cast<
1397         Option6AddrLst>(vendor_opt->getOption(DOCSIS3_V6_TFTP_SERVERS));
1398     ASSERT_TRUE(tftp);
1399 
1400     // Address specified in the host scope should be used.
1401     Option6AddrLst::AddressContainer addrs = tftp->getAddresses();
1402     ASSERT_EQ(addrs.size(), 1);
1403     EXPECT_EQ("3000:1::234", addrs[0].toText());
1404 }
1405 
1406 void
testGlobalClassSubnetPoolSelection(const int config_idx,const std::string & first_address,const std::string & second_address)1407 HostTest::testGlobalClassSubnetPoolSelection(const int config_idx,
1408                                              const std::string& first_address,
1409                                              const std::string& second_address) {
1410     Dhcp6Client client_resrv;
1411 
1412     // Use DUID for which we have host reservation including client class.
1413     client_resrv.setDUID("01:02:03:05");
1414 
1415     ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[config_idx], *client_resrv.getServer()));
1416 
1417     // This client should be given an address from the 2001:db8:1::/64 subnet.
1418     // Let's use the 2001:db8:2::10 as a hint to make sure that the server
1419     // refuses allocating it and uses the sole pool available for this
1420     // client.
1421     client_resrv.requestAddress(1, IOAddress(second_address));
1422     ASSERT_NO_THROW(client_resrv.doSARR());
1423     ASSERT_EQ(1, client_resrv.getLeaseNum());
1424     Lease6 lease_client = client_resrv.getLease(0);
1425     EXPECT_EQ(first_address, lease_client.addr_.toText());
1426 
1427     // This client has no reservation and therefore should be
1428     // assigned to the unreserved_class and be given an address
1429     // from the other pool.
1430     Dhcp6Client client_no_resrv(client_resrv.getServer());
1431     client_no_resrv.setDUID("01:02:03:04");
1432 
1433     // Let's use the address of 2001:db8:1::10 as a hint to make sure that the
1434     // server refuses it in favor of the 2001:db8:2::10.
1435     client_no_resrv.requestAddress(1, IOAddress(first_address));
1436     ASSERT_NO_THROW(client_no_resrv.doSARR());
1437     ASSERT_EQ(1, client_no_resrv.getLeaseNum());
1438     lease_client = client_no_resrv.getLease(0);
1439     EXPECT_EQ(second_address, lease_client.addr_.toText());
1440 }
1441 
1442 void
testMultipleClientsRace(const std::string & duid1,const std::string & duid2)1443 HostTest::testMultipleClientsRace(const std::string& duid1,
1444                                   const std::string& duid2) {
1445     Dhcp6Client client1;
1446     client1.setDUID(duid1);
1447     ASSERT_NO_THROW(configure(CONFIGS[13], *client1.getServer()));
1448     // client1 performs 4-way exchange to get the reserved lease.
1449     requestIA(client1, Hint(IAID(1), "2001:db8:1::15"));
1450     ASSERT_NO_THROW(client1.doSARR());
1451 
1452     // Make sure the client has obtained reserved lease.
1453     ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
1454 
1455     // Create another client that has a reservation for the same
1456     // IP address.
1457     Dhcp6Client client2(client1.getServer());
1458     client2.setDUID(duid2);
1459     requestIA(client2, Hint(IAID(1), "2001:db8:1::15"));
1460 
1461     // client2 performs 4-way exchange.
1462     ASSERT_NO_THROW(client2.doSARR());
1463 
1464     // Make sure the client didn't get the reserved lease. This lease has been
1465     // already taken by the client1.
1466     EXPECT_FALSE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
1467 
1468     // Make sure the client2 got a lease from the configured pool.
1469     EXPECT_TRUE(client2.hasLeaseForAddressRange(IOAddress("2001:db8:1::10"),
1470                                                 IOAddress("2001:db8:1::200")));
1471 }
1472 
1473 void
requestEmptyIAs(Dhcp6Client & client)1474 HostTest::requestEmptyIAs(Dhcp6Client& client) {
1475     // Create IAs with IAIDs between 1 and 6.
1476     client.requestAddress(1);
1477     client.requestAddress(2);
1478     client.requestAddress(3);
1479     client.requestPrefix(4);
1480     client.requestPrefix(5);
1481     client.requestPrefix(6);
1482 }
1483 
1484 void
sarrTest(Dhcp6Client & client,const std::string & exp_address,const std::string & exp_hostname)1485 HostTest::sarrTest(Dhcp6Client& client, const std::string& exp_address,
1486                    const std::string& exp_hostname) {
1487     // Perform 4-way exchange.
1488     ASSERT_NO_THROW(client.doSARR());
1489 
1490     // Verify that the client got a dynamic address
1491     ASSERT_EQ(1, client.getLeaseNum());
1492     Lease6 lease_client = client.getLease(0);
1493     EXPECT_EQ(exp_address, lease_client.addr_.toText());
1494 
1495     // Check that the server recorded the lease
1496     // and that the server lease has expected hostname.
1497     Lease6Ptr lease_server = checkLease(lease_client);
1498     ASSERT_TRUE(lease_server);
1499     EXPECT_EQ(exp_hostname, lease_server->hostname_);
1500 }
1501 
1502 
1503 // Test basic SARR scenarios against a server configured with one subnet
1504 // containing two reservations.  One reservation with a hostname, one
1505 // without a hostname. Scenarios:
1506 //
1507 // - Verify that a client when matched to a host reservation with a hostname
1508 // gets that reservation and the lease hostname matches the reserved hostname
1509 //
1510 // - Verify that a client when matched to a host reservation without a hostname
1511 // gets that reservation and the lease hostname is blank
1512 //
1513 // - Verify that a client that does not match a host reservation gets a dynamic
1514 // lease and the hostname for the lease is blank.
1515 //
TEST_F(HostTest,basicSarrs)1516 TEST_F(HostTest, basicSarrs) {
1517     Dhcp6Client client;
1518     configure(CONFIGS[0], *client.getServer());
1519 
1520     const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
1521         getCfgSubnets6()->getAll();
1522     ASSERT_EQ(1, subnets->size());
1523 
1524     // Configure client to request IA_NA and append IA_NA option
1525     // to the client's message.
1526     client.setDUID("01:02:03:04");
1527     client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
1528 
1529     // Perform 4-way exchange.
1530     ASSERT_NO_THROW(client.doSARR());
1531 
1532     // Verify that the client we got the reserved address
1533     ASSERT_EQ(1, client.getLeaseNum());
1534     Lease6 lease_client = client.getLease(0);
1535     EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText());
1536 
1537     // Check that the server recorded the lease.
1538     // and lease has reserved hostname
1539     Lease6Ptr lease_server = checkLease(lease_client);
1540     ASSERT_TRUE(lease_server);
1541     EXPECT_EQ("alice", lease_server->hostname_);
1542 
1543     // Now redo the client, adding one to the DUID
1544     client.clearConfig();
1545     client.modifyDUID();
1546 
1547     // Perform 4-way exchange.
1548     ASSERT_NO_THROW(client.doSARR());
1549 
1550     // Verify that the client we got the reserved address
1551     ASSERT_EQ(1, client.getLeaseNum());
1552     lease_client = client.getLease(0);
1553     EXPECT_EQ("2001:db8:1:1::babf", lease_client.addr_.toText());
1554 
1555     // Check that the server recorded the lease.
1556     // and that the server lease has NO hostname
1557     lease_server = checkLease(lease_client);
1558     ASSERT_TRUE(lease_server);
1559     EXPECT_EQ("", lease_server->hostname_);
1560 
1561     // Now redo the client with yet another DUID and verify that
1562     // we get a dynamic address.
1563     client.clearConfig();
1564     client.modifyDUID();
1565     client.clearRequestedIAs();
1566     client.requestAddress(1234);
1567 
1568     // Perform 4-way exchange.
1569     ASSERT_NO_THROW(client.doSARR());
1570 
1571     // Verify that the client got a dynamic address
1572     ASSERT_EQ(1, client.getLeaseNum());
1573     lease_client = client.getLease(0);
1574     EXPECT_EQ("2001:db8:1:1::", lease_client.addr_.toText());
1575 
1576     // Check that the server recorded the lease.
1577     // and that the server lease has NO hostname
1578     lease_server = checkLease(lease_client);
1579     ASSERT_TRUE(lease_server);
1580     EXPECT_EQ("", lease_server->hostname_);
1581 }
1582 
1583 // Test basic SARR and renew situation with a client that matches a host
1584 // reservation
TEST_F(HostTest,sarrAndRenew)1585 TEST_F(HostTest, sarrAndRenew) {
1586     Dhcp6Client client;
1587 
1588     configure(CONFIGS[0], *client.getServer());
1589 
1590     // Configure client to request IA_NA.
1591     client.requestAddress();
1592 
1593     const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
1594         getCfgSubnets6()->getAll();
1595     ASSERT_EQ(1, subnets->size());
1596 
1597     // Configure client to request IA_NA and aAppend IA_NA option
1598     //  to the client's message.
1599     client.setDUID("01:02:03:04");
1600     client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
1601 
1602     // Perform 4-way exchange.
1603     ASSERT_NO_THROW(client.doSARR());
1604 
1605     // Now play with time
1606     client.fastFwdTime(1000);
1607 
1608     // Verify that the client we got the reserved address
1609     ASSERT_EQ(1, client.getLeaseNum());
1610     Lease6 lease_client = client.getLease(0);
1611     EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText());
1612 
1613     // Do not send the hint while renewing.
1614     client.clearRequestedIAs();
1615 
1616     // Send Renew message to the server.
1617     ASSERT_NO_THROW(client.doRenew());
1618 
1619     // Verify that we got an extended lease back
1620     ASSERT_EQ(1, client.getLeaseNum());
1621     Lease6 lease_client2 = client.getLease(0);
1622     EXPECT_EQ("2001:db8:1:1::babe", lease_client2.addr_.toText());
1623 
1624     // The client's lease should have been extended. The client will
1625     // update the cltt to current time when the lease gets extended.
1626     ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
1627 
1628     // Make sure, that the client's lease matches the lease held by the
1629     // server and that we have the reserved host name.
1630     Lease6Ptr lease_server2 = checkLease(lease_client2);
1631     EXPECT_TRUE(lease_server2);
1632     EXPECT_EQ("alice", lease_server2->hostname_);
1633 }
1634 
1635 // Test basic SARR and rebind situation with a client that matches a host
1636 // reservation.
TEST_F(HostTest,sarrAndRebind)1637 TEST_F(HostTest, sarrAndRebind) {
1638     Dhcp6Client client;
1639 
1640     configure(CONFIGS[0], *client.getServer());
1641 
1642     // Configure client to request IA_NA.
1643     client.requestAddress();
1644 
1645     const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
1646         getCfgSubnets6()->getAll();
1647     ASSERT_EQ(1, subnets->size());
1648 
1649     // Configure client to request IA_NA and aAppend IA_NA option
1650     //  to the client's message.
1651     client.setDUID("01:02:03:04");
1652     client.requestAddress(1234, IOAddress("2001:db8:1:1::dead:beef"));
1653 
1654     // Perform 4-way exchange.
1655     ASSERT_NO_THROW(client.doSARR());
1656 
1657     // Now play with time
1658     client.fastFwdTime(1000);
1659 
1660     // Verify that the client we got the reserved address
1661     ASSERT_EQ(1, client.getLeaseNum());
1662     Lease6 lease_client = client.getLease(0);
1663     EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText());
1664 
1665     // Do not send the hint while renewing.
1666     client.clearRequestedIAs();
1667 
1668     // Send Rebind message to the server.
1669     ASSERT_NO_THROW(client.doRebind());
1670 
1671     // Verify that we got an extended lease back
1672     ASSERT_EQ(1, client.getLeaseNum());
1673     Lease6 lease_client2 = client.getLease(0);
1674     EXPECT_EQ("2001:db8:1:1::babe", lease_client2.addr_.toText());
1675 
1676     // The client's lease should have been extended. The client will
1677     // update the cltt to current time when the lease gets extended.
1678     ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
1679 
1680     // Make sure, that the client's lease matches the lease held by the
1681     // server and that we have the reserved host name.
1682     Lease6Ptr lease_server2 = checkLease(lease_client2);
1683     EXPECT_TRUE(lease_server2);
1684     EXPECT_EQ("alice", lease_server2->hostname_);
1685 }
1686 
1687 // This test verifies that the host reservation by DUID is found by the
1688 // server.
TEST_F(HostTest,reservationByDUID)1689 TEST_F(HostTest, reservationByDUID) {
1690     Dhcp6Client client;
1691     // Set DUID matching the one used to create host reservations.
1692     client.setDUID("01:02:03:05");
1693     // Run the actual test.
1694     testReservationByIdentifier(client, 1, "2001:db8:1::2");
1695 }
1696 
1697 // This test verifies that the host reservation by HW address is found
1698 // by the server.
TEST_F(HostTest,reservationByHWAddress)1699 TEST_F(HostTest, reservationByHWAddress) {
1700     Dhcp6Client client;
1701     // Set link local address for the client which the server will
1702     // use to decode the HW address as 38:60:77:d5:ff:ee. This
1703     // decoded address will be used to search for host reservations.
1704     client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee"));
1705     // Run the actual test.
1706     testReservationByIdentifier(client, 1, "2001:db8:1::1");
1707 }
1708 
1709 // This test verifies that order in which host identifiers are used to
1710 // retrieve host reservations can be controlled.
TEST_F(HostTest,hostIdentifiersOrder)1711 TEST_F(HostTest, hostIdentifiersOrder) {
1712     Dhcp6Client client;
1713     // Set DUID matching the one used to create host reservations.
1714     client.setDUID("01:02:03:05");
1715     // Set link local address for the client which the server will
1716     // use to decode the HW address as 38:60:77:d5:ff:ee. This
1717     // decoded address will be used to search for host reservations.
1718     client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee"));
1719     testReservationByIdentifier(client, 2, "2001:db8:1::2");
1720 }
1721 
1722 // This test checks that host specific options override subnet specific
1723 // and pool specific options. Overridden options are requested with Option
1724 // Request option (Information-request case).
TEST_F(HostTest,overrideRequestedOptionsInformationRequest)1725 TEST_F(HostTest, overrideRequestedOptionsInformationRequest) {
1726     testOverrideRequestedOptions(DHCPV6_INFORMATION_REQUEST);
1727 }
1728 
1729 // This test checks that host specific options override subnet specific
1730 // and pool specific options. Overridden options are requested with Option
1731 // Request option (Request case).
TEST_F(HostTest,overrideRequestedOptionsRequest)1732 TEST_F(HostTest, overrideRequestedOptionsRequest) {
1733     testOverrideRequestedOptions(DHCPV6_REQUEST);
1734 }
1735 
1736 // This test checks that host specific options override subnet specific
1737 // and pool specific options. Overridden options are requested with Option
1738 // Request option (Renew case).
TEST_F(HostTest,overrideRequestedOptionsRenew)1739 TEST_F(HostTest, overrideRequestedOptionsRenew) {
1740     testOverrideRequestedOptions(DHCPV6_RENEW);
1741 }
1742 
1743 // This test checks that host specific options override subnet specific
1744 // and pool specific options. Overridden options are requested with Option
1745 // Request option (Rebind case).
TEST_F(HostTest,overrideRequestedOptionsRebind)1746 TEST_F(HostTest, overrideRequestedOptionsRebind) {
1747     testOverrideRequestedOptions(DHCPV6_REBIND);
1748 }
1749 
1750 // This test checks that client receives options when they are
1751 // solely defined in the host scope and not in the global or subnet
1752 // scope (Information-request case).
TEST_F(HostTest,testHostOnlyOptionsInformationRequest)1753 TEST_F(HostTest, testHostOnlyOptionsInformationRequest) {
1754     testHostOnlyOptions(DHCPV6_INFORMATION_REQUEST);
1755 }
1756 
1757 // This test checks that client receives options when they are
1758 // solely defined in the host scope and not in the global or subnet
1759 // scope (Request case).
TEST_F(HostTest,testHostOnlyOptionsRequest)1760 TEST_F(HostTest, testHostOnlyOptionsRequest) {
1761     testHostOnlyOptions(DHCPV6_REQUEST);
1762 }
1763 
1764 // This test checks that client receives options when they are
1765 // solely defined in the host scope and not in the global or subnet
1766 // scope (Renew case).
TEST_F(HostTest,testHostOnlyOptionsRenew)1767 TEST_F(HostTest, testHostOnlyOptionsRenew) {
1768     testHostOnlyOptions(DHCPV6_RENEW);
1769 }
1770 
1771 // This test checks that client receives options when they are
1772 // solely defined in the host scope and not in the global or subnet
1773 // scope (Rebind case).
TEST_F(HostTest,testHostOnlyOptionsRebind)1774 TEST_F(HostTest, testHostOnlyOptionsRebind) {
1775     testHostOnlyOptions(DHCPV6_REBIND);
1776 }
1777 
1778 // This test checks that host specific vendor options override vendor
1779 // options defined in the global scope (Request case).
TEST_F(HostTest,overrideVendorOptionsRequest)1780 TEST_F(HostTest, overrideVendorOptionsRequest) {
1781     testOverrideVendorOptions(DHCPV6_REQUEST);
1782 }
1783 
1784 // This test checks that host specific vendor options override vendor
1785 // options defined in the global scope (Renew case).
TEST_F(HostTest,overrideVendorOptionsRenew)1786 TEST_F(HostTest, overrideVendorOptionsRenew) {
1787     testOverrideVendorOptions(DHCPV6_RENEW);
1788 }
1789 
1790 // This test checks that host specific vendor options override vendor
1791 // options defined in the global scope (Rebind case).
TEST_F(HostTest,overrideVendorOptionsRebind)1792 TEST_F(HostTest, overrideVendorOptionsRebind) {
1793     testOverrideVendorOptions(DHCPV6_REBIND);
1794 }
1795 
1796 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs
1797 // without hints and the server should return those IAs with 3 reserved
1798 // addresses and 3 reserved prefixes.
TEST_F(HostTest,multipleIAsSolicit)1799 TEST_F(HostTest, multipleIAsSolicit) {
1800     testMultipleIAs(do_solicit_,
1801                     Reservation("2001:db8:1:1::1"),
1802                     Reservation("2001:db8:1:1::2"),
1803                     Reservation("2001:db8:1:1::3"),
1804                     Reservation("3000:1:1::/64"),
1805                     Reservation("3000:1:2::/64"),
1806                     Reservation("3000:1:3::/64"));
1807 }
1808 
1809 // In this test the client performs 4-way exchange, sending 3 IA_NAs
1810 // and 3 IA_PDs without hints. The server should return those IAs
1811 // with 3 reserved addresses and 3 reserved prefixes.
TEST_F(HostTest,multipleIAsRequest)1812 TEST_F(HostTest, multipleIAsRequest) {
1813     testMultipleIAs(do_solicit_request_,
1814                     Reservation("2001:db8:1:1::1"),
1815                     Reservation("2001:db8:1:1::2"),
1816                     Reservation("2001:db8:1:1::3"),
1817                     Reservation("3000:1:1::/64"),
1818                     Reservation("3000:1:2::/64"),
1819                     Reservation("3000:1:3::/64"));
1820 }
1821 
1822 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs
1823 // without hints. The server has 2 reservations for addresses and
1824 // 2 reservations for prefixes for this client. The server should
1825 // assign reserved addresses and prefixes to the client, and return
1826 // them in 2 IA_NAs and 2 IA_PDs. For the remaining IA_NA and IA_PD
1827 // the server should allocate address and prefix from a dynamic pools.
TEST_F(HostTest,staticAndDynamicIAs)1828 TEST_F(HostTest, staticAndDynamicIAs) {
1829     testMultipleIAs(do_solicit_,
1830                     Reservation("2001:db8:1:1::2"),
1831                     Reservation("2001:db8:1:1::3"),
1832                     Reservation("3000:1:1::/64"),
1833                     Reservation("3000:1:3::/64"));
1834 }
1835 
1836 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1837 // The client includes an address hint for IAID = 1, a prefix length
1838 // hint for the IAID = 5, and the prefix hint for IAID = 6. The hints
1839 // match the reserved resources and should be allocated for the client.
TEST_F(HostTest,multipleIAsHintsForReservations)1840 TEST_F(HostTest, multipleIAsHintsForReservations) {
1841     testMultipleIAs(do_solicit_,
1842                     Reservation("2001:db8:1:1::1"),
1843                     Reservation("2001:db8:1:1::2"),
1844                     Reservation("2001:db8:1:1::3"),
1845                     Reservation("3000:1:1::/64"),
1846                     Reservation("3000:1:2::/64"),
1847                     Reservation("3000:1:3::/64"),
1848                     StrictIAIDChecking::NO(),
1849                     Hint(IAID(1), "2001:db8:1:1::2"),
1850                     Hint(IAID(5), "::/64"),
1851                     Hint(IAID(6), "3000:1:1::/64"));
1852 }
1853 
1854 // In this test the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1855 // The client includes one address hint for IAID = 1 and one
1856 // prefix hint for IAID = 6. The hints point to an address and prefix
1857 // from the dynamic pools, but because the server has reservations
1858 // for other addresses and prefixes outside the pool, the address
1859 // and prefix specified as hint should not be allocated. Instead
1860 // the server should allocate reserved leases.
TEST_F(HostTest,multipleIAsHintsInPool)1861 TEST_F(HostTest, multipleIAsHintsInPool) {
1862     testMultipleIAs(do_solicit_,
1863                     Reservation("2001:db8:1:1::1"),
1864                     Reservation("2001:db8:1:1::2"),
1865                     Reservation("2001:db8:1:1::3"),
1866                     Reservation("3000:1:1::/64"),
1867                     Reservation("3000:1:2::/64"),
1868                     Reservation("3000:1:3::/64"),
1869                     StrictIAIDChecking::NO(),
1870                     Hint(IAID(1), "2001:db8:1::2"),
1871                     Hint(IAID(6), "3001::/64"));
1872 }
1873 
1874 // In this test, the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1875 // The client includes one address hint for which the client has
1876 // reservation, one prefix hint for which the client has reservation,
1877 // one hint for an address from the dynamic pool and one hint for a
1878 // prefix from a dynamic pool. The server has reservations for 2
1879 // addresses and 2 prefixes. The server should allocate reserved
1880 // leases and address and prefix from a dynamic pool, which client
1881 // included as hints.
TEST_F(HostTest,staticAndDynamicIAsHints)1882 TEST_F(HostTest, staticAndDynamicIAsHints) {
1883     testMultipleIAs(do_solicit_,
1884                     Reservation("2001:db8:1:1::1"),
1885                     Reservation("2001:db8:1:1::3"),
1886                     Reservation("3000:1:1::/64"),
1887                     Reservation("3000:1:2::/64"),
1888                     Reservation::UNSPEC(),
1889                     Reservation::UNSPEC(),
1890                     StrictIAIDChecking::NO(),
1891                     Hint(IAID(1), "2001:db8:1::2"),
1892                     Hint(IAID(3), "2001:db8:1:1::1"),
1893                     Hint(IAID(5), "3001::/64"),
1894                     Hint(IAID(6), "3000::/64"));
1895 }
1896 
1897 // In this test, the client sends Solicit with 3 IA_NAs and 3 IA_PDs.
1898 // The server has reservation for two addresses and two prefixes for
1899 // this client. The client includes address hint in the third IA_NA
1900 // and in the third IA_PD. The server should offer 2 addresses in the
1901 // first two IA_NAs and 2 prefixes in the two IA_PDs. The server should
1902 // respect hints provided within the 3rd IA_NA and 3rd IA_PD. The server
1903 // wouldn't respect hints if they were provided within 1st or 2nd IA of
1904 // a given type, because the server always tries to allocate the
1905 // reserved leases in the first place.
TEST_F(HostTest,staticAndDynamicIAsHintsStrictIAIDCheck)1906 TEST_F(HostTest, staticAndDynamicIAsHintsStrictIAIDCheck) {
1907     testMultipleIAs(do_solicit_,
1908                     Reservation("2001:db8:1:1::1"),
1909                     Reservation("2001:db8:1:1::2"),
1910                     Reservation("3000:1:1::/64"),
1911                     Reservation("3000:1:2::/64"),
1912                     Reservation::UNSPEC(),
1913                     Reservation::UNSPEC(),
1914                     StrictIAIDChecking::YES(),
1915                     Hint(IAID(3), "2001:db8:1::5"),
1916                     Hint(IAID(6), "3001:0:0:10::/64"));
1917 }
1918 
1919 // In this test, the client performs 4-way exchange and includes 3 IA_NAs
1920 // and 3 IA_PDs. The client provides no hints. The server has 3 address
1921 // reservations and 3 prefix reservations for this client and allocates them
1922 // as a result of 4-way exchange. The client then sends a Renew and the server
1923 // should renew all leases allocated for the client during the 4-way exchange.
TEST_F(HostTest,multipleIAsRenew)1924 TEST_F(HostTest, multipleIAsRenew) {
1925     // 4-way exchange
1926     testMultipleIAs(do_solicit_request_,
1927                     Reservation("2001:db8:1:1::1"),
1928                     Reservation("2001:db8:1:1::2"),
1929                     Reservation("2001:db8:1:1::3"),
1930                     Reservation("3000:1:1::/64"),
1931                     Reservation("3000:1:2::/64"),
1932                     Reservation("3000:1:3::/64"));
1933 
1934     // Renew
1935     ASSERT_NO_THROW(client_.doRenew());
1936 
1937     // Make sure that the client still has the same leases.
1938     ASSERT_EQ(6, client_.getLeaseNum());
1939 
1940     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1")));
1941     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2")));
1942     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
1943     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64));
1944     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64));
1945     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
1946 }
1947 
1948 // In this test, the client performs 4-way exchange and includes 3 IA_NAs
1949 // and IA_PDs. The server has 3 address and 3 prefix reservations for the
1950 // client and allocates them all. Once the 4-way exchange is complete,
1951 // the client sends Solicit in which it specifies hints for all IAs. The
1952 // hints are for the reserved addresses but some of them are included in
1953 // different IAs than they are assigned to. The server should ignore hints
1954 // and respond with currently assigned leases.
TEST_F(HostTest,multipleIAsSolicitAfterAcquisition)1955 TEST_F(HostTest, multipleIAsSolicitAfterAcquisition) {
1956     // 4-way exchange
1957     testMultipleIAs(do_solicit_request_,
1958                     Reservation("2001:db8:1:1::1"),
1959                     Reservation("2001:db8:1:1::2"),
1960                     Reservation("2001:db8:1:1::3"),
1961                     Reservation("3000:1:1::/64"),
1962                     Reservation("3000:1:2::/64"),
1963                     Reservation("3000:1:3::/64"));
1964 
1965     client_.clearRequestedIAs();
1966 
1967     // Specify hints.
1968 
1969     // "2001:db8:1:1::1" is allocated for IAID = 1 but we specify it as
1970     // a hint for IAID = 3 and so on.
1971     requestIA(client_, Hint(IAID(3), "2001:db8:1:1::1"));
1972     requestIA(client_, Hint(IAID(2), "2001:db8:1:1::2"));
1973     requestIA(client_, Hint(IAID(1), "2001:db8:1:1::3"));
1974     requestIA(client_, Hint(IAID(6), "3000:1:1::/64"));
1975     requestIA(client_, Hint(IAID(5), "3000:1:2::/64"));
1976     requestIA(client_, Hint(IAID(4), "3000:1:3::/64"));
1977 
1978     // Send Solicit with hints as specified above.
1979     ASSERT_NO_THROW(do_solicit_());
1980 
1981     // Make sure that the client still has the same leases and the leases
1982     // should be assigned to the same IAs.
1983     ASSERT_EQ(6, client_.getLeaseNum());
1984 
1985     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1"),
1986                                            IAID(1)));
1987     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2"),
1988                                            IAID(2)));
1989     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3"),
1990                                            IAID(3)));
1991     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64,
1992                                           IAID(4)));
1993     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64,
1994                                           IAID(5)));
1995     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64,
1996                                           IAID(6)));
1997 }
1998 
1999 // In this test, the client performs 4-way exchange and includes 3 IA_NAs and
2000 // 3 IA_PDs and includes no hints. The server has reservations for 2 addresses
2001 // and 2 prefixes for this client. The server allocates reserved leases and
2002 // an additional address and prefix from the dynamic pools. The server is
2003 // reconfigured to add 3rd address and 3rd prefix reservation for the client.
2004 // The client sends a Renew and the server should renew existing leases and
2005 // allocate newly reserved address and prefix, replacing the previously
2006 // allocated dynamic leases. For both dynamically allocated leases, the
2007 // server should return IAs with zero lifetimes.
TEST_F(HostTest,appendReservationDuringRenew)2008 TEST_F(HostTest, appendReservationDuringRenew) {
2009     // 4-way exchange to acquire 4 reserved leases and 2 dynamic leases.
2010     testMultipleIAs(do_solicit_request_,
2011                     Reservation("2001:db8:1:1::1"),
2012                     Reservation("2001:db8:1:1::2"),
2013                     Reservation("3000:1:1::/64"),
2014                     Reservation("3000:1:2::/64"));
2015 
2016     // The server must have not lease for the address and prefix for which
2017     // we will later make reservations, because these are outside of the
2018     // dynamic pool.
2019     ASSERT_FALSE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
2020     ASSERT_FALSE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
2021 
2022     // Retrieve leases from the dynamic pools and store them so as we can
2023     // later check that they were returned with zero lifetimes when the
2024     // reservations are added.
2025     std::vector<Lease6> leases =
2026         client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
2027                                         IOAddress("2001:db8:1::10"));
2028     ASSERT_EQ(1, leases.size());
2029     IOAddress dynamic_address_lease = leases[0].addr_;
2030 
2031     leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
2032     ASSERT_EQ(1, leases.size());
2033     IOAddress dynamic_prefix_lease = leases[0].addr_;
2034 
2035     // Add two additional reservations.
2036     std::string c = configString(*client_.getDuid(),
2037                                  Reservation("2001:db8:1:1::1"),
2038                                  Reservation("2001:db8:1:1::2"),
2039                                  Reservation("2001:db8:1:1::3"),
2040                                  Reservation("3000:1:1::/64"),
2041                                  Reservation("3000:1:2::/64"),
2042                                  Reservation("3000:1:3::/64"));
2043 
2044     ASSERT_NO_THROW(configure(c, *client_.getServer()));
2045 
2046     // Client renews and includes all leases it currently has in the IAs.
2047     ASSERT_NO_THROW(client_.doRenew());
2048 
2049     // The expectation is that the server allocated two new reserved leases to
2050     // the client and removed leases allocated from the dynamic pools. The
2051     // number if leases in the server configuration should include those that
2052     // are returned with zero lifetimes. Hence, the total number of leases
2053     // should be equal to 6 + 2 = 8.
2054     ASSERT_EQ(8, client_.getLeaseNum());
2055 
2056     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1")));
2057     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2")));
2058     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
2059     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64));
2060     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64));
2061     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
2062 
2063     // Make sure that the replaced leases have been returned with zero lifetimes.
2064     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(dynamic_address_lease));
2065     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(dynamic_prefix_lease, 64));
2066 
2067     // Now let's test the scenario when all reservations are removed for this
2068     // client.
2069     c = configString(*client_.getDuid());
2070 
2071     ASSERT_NO_THROW(configure(c, *client_.getServer()));
2072 
2073     // An attempt to renew should result in removing all allocated leases,
2074     // because these leases are no longer reserved and they don't belong to the
2075     // dynamic pools.
2076     ASSERT_NO_THROW(client_.doRenew());
2077 
2078     // The total number of leases should include removed leases and newly
2079     // allocated once, i.e. 6 + 6 = 12.
2080     ASSERT_EQ(12, client_.getLeaseNum());
2081 
2082     // All removed leases should be returned with zero lifetimes.
2083     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1:1::1")));
2084     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1:1::2")));
2085     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1:1::3")));
2086     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000:1:1::"), 64));
2087     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000:1:2::"), 64));
2088     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000:1:3::"), 64));
2089 
2090     // Make sure that all address leases are within the dynamic pool range.
2091     leases = client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
2092                                             IOAddress("2001:db8:1::10"));
2093     EXPECT_EQ(3, leases.size());
2094 
2095     // Make sure that all prefix leases are also within the dynamic pool range.
2096     leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
2097     EXPECT_EQ(3, leases.size());
2098 }
2099 
2100 // In this test, the client performs 4-way exchange and includes 3 IA_NAs
2101 // and 3 IA_PDs. Initially, the server has 2 address reservations and
2102 // 2 prefix reservations for this client. The server allocates the 2
2103 // reserved addresses to the first 2 IA_NAs and 2 reserved prefixes to the
2104 // first two IA_PDs. The server is reconfigured and 2 new reservations are
2105 // inserted: new address reservation before existing address reservations
2106 // and prefix reservation before existing prefix reservations.
2107 // The server should detect that leases already exist for reserved addresses
2108 // and prefixes and it should not remove existing leases. Instead, it should
2109 // replace dynamically allocated leases with newly added reservations
TEST_F(HostTest,insertReservationDuringRenew)2110 TEST_F(HostTest, insertReservationDuringRenew) {
2111     // 4-way exchange to acquire 4 reserved leases and 2 dynamic leases.
2112     testMultipleIAs(do_solicit_request_,
2113                     Reservation("2001:db8:1:1::1"),
2114                     Reservation("2001:db8:1:1::2"),
2115                     Reservation("3000:1:1::/64"),
2116                     Reservation("3000:1:2::/64"));
2117 
2118     // The server must have not lease for the address and prefix for which
2119     // we will later make reservations, because these are outside of the
2120     // dynamic pool.
2121     ASSERT_FALSE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3")));
2122     ASSERT_FALSE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64));
2123 
2124     // Retrieve leases from the dynamic pools and store them so as we can
2125     // later check that they were returned with zero lifetimes when the
2126     // reservations are added.
2127     std::vector<Lease6> leases =
2128         client_.getLeasesByAddressRange(IOAddress("2001:db8:1::1"),
2129                                         IOAddress("2001:db8:1::10"));
2130     ASSERT_EQ(1, leases.size());
2131     IOAddress dynamic_address_lease = leases[0].addr_;
2132 
2133     leases = client_.getLeasesByPrefixPool(IOAddress("3001::"), 32, 64);
2134     ASSERT_EQ(1, leases.size());
2135     IOAddress dynamic_prefix_lease = leases[0].addr_;
2136 
2137     // Add two additional reservations.
2138     std::string c = configString(*client_.getDuid(),
2139                                  Reservation("2001:db8:1:1::3"),
2140                                  Reservation("2001:db8:1:1::1"),
2141                                  Reservation("2001:db8:1:1::2"),
2142                                  Reservation("3000:1:3::/64"),
2143                                  Reservation("3000:1:1::/64"),
2144                                  Reservation("3000:1:2::/64"));
2145 
2146     ASSERT_NO_THROW(configure(c, *client_.getServer()));
2147 
2148     // Client renews and includes all leases it currently has in the IAs.
2149     ASSERT_NO_THROW(client_.doRenew());
2150 
2151     // The expectation is that the server allocated two new reserved leases to
2152     // the client and removed leases allocated from the dynamic pools. The
2153     // number if leases in the server configuration should include those that
2154     // are returned with zero lifetimes. Hence, the total number of leases
2155     // should be equal to 6 + 2 = 8.
2156     ASSERT_EQ(8, client_.getLeaseNum());
2157 
2158     // Even though the new reservations have been added before existing
2159     // reservations, the server should assign them to the IAs with
2160     // IAID = 3 (for address) and IAID = 6 (for prefix).
2161     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::1"),
2162                                            IAID(1)));
2163     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::2"),
2164                                            IAID(2)));
2165     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1:1::3"),
2166                                            IAID(3)));
2167     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:1::"), 64,
2168                                           IAID(4)));
2169     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:2::"), 64,
2170                                           IAID(5)));
2171     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3000:1:3::"), 64,
2172                                           IAID(6)));
2173 
2174     // Make sure that the replaced leases have been returned with zero lifetimes.
2175     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForAddress(dynamic_address_lease));
2176     EXPECT_TRUE(client_.hasLeaseWithZeroLifetimeForPrefix(dynamic_prefix_lease, 64));
2177 }
2178 
2179 // In this test there are two clients. One client obtains two leases: one
2180 // for a prefix, another one for an address. The server is reconfigured
2181 // to make 4 reservations to a different client. Two of those reservations
2182 // are for the prefix and the address assigned to the first client. The
2183 // second client performs 4-way exchange and the server detects that two
2184 // reserved leases are not available because they are in use by another
2185 // client. The server assigns available address and prefix and an address
2186 // and prefix from dynamic pool. The first client renews and the server
2187 // detects that the renewed leases are reserved for another client. As
2188 // a result, the client obtains an address and prefix from the dynamic
2189 // pools. The second client renews and it obtains all reserved
2190 // addresses and prefixes.
TEST_F(HostTest,multipleIAsConflict)2191 TEST_F(HostTest, multipleIAsConflict) {
2192     Dhcp6Client client;
2193     client.setDUID("01:02:03:05");
2194 
2195     // Create configuration without any reservations.
2196     std::string c = configString(*client_.getDuid());
2197 
2198     ASSERT_NO_THROW(configure(c, *client_.getServer()));
2199 
2200     // First client performs 4-way exchange and obtains an address and
2201     // prefix indicated in hints.
2202     requestIA(client, Hint(IAID(1), "2001:db8:1::1"));
2203     requestIA(client, Hint(IAID(2), "3001:0:0:10::/64"));
2204 
2205     ASSERT_NO_THROW(client.doSARR());
2206 
2207     // Make sure the client has obtained requested leases.
2208     ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::1"), IAID(1)));
2209     ASSERT_TRUE(client.hasLeaseForPrefix(IOAddress("3001:0:0:10::"), 64,
2210                                          IAID(2)));
2211 
2212     // Reconfigure the server to make reservations for the second client.
2213     // The reservations include a prefix and address acquired by the
2214     // first client in the previous transaction.
2215     c = configString(*client_.getDuid(),
2216                      Reservation("2001:db8:1::1"),
2217                      Reservation("2001:db8:1::2"),
2218                      Reservation("3001:0:0:9::/64"),
2219                      Reservation("3001:0:0:10::/64"));
2220 
2221     ASSERT_NO_THROW(configure(c, *client_.getServer()));
2222 
2223     // Configure the second client to send two IA_NAs and two IA_PDs with
2224     // IAIDs from 1 to 4.
2225     client_.requestAddress(1);
2226     client_.requestAddress(2);
2227     client_.requestPrefix(3);
2228     client_.requestPrefix(4);
2229 
2230     // Perform 4-way exchange.
2231     ASSERT_NO_THROW(do_solicit_request_());
2232 
2233     // The client should have obtained 4 leases: two prefixes and two addresses.
2234     ASSERT_EQ(4, client_.getLeaseNum());
2235 
2236     // The address "2001:db8:1::2" is reserved and available so the
2237     // server should have assigned it.
2238     ASSERT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::2"),
2239                                            IAID(1)));
2240     // The address "2001:db8:1::1" was hijacked by another client so it
2241     // must not be assigned to this client.
2242     ASSERT_FALSE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::1")));
2243     // This client should have got an address from the dynamic pool excluding
2244     // two addresses already assigned, i.e. excluding "2001:db8:1::1" and
2245     // "2001:db8:1::2".
2246     ASSERT_TRUE(client_.hasLeaseForAddressRange(IOAddress("2001:db8:1::3"),
2247                                                 IOAddress("2001:db8:1::10")));
2248 
2249     // Same story with prefixes.
2250     ASSERT_TRUE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:9::"), 64,
2251                                           IAID(3)));
2252     ASSERT_FALSE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:10::"), 64));
2253 
2254 
2255     // Now that the reservations have been made, the first client should get
2256     // non-reserved leases upon renewal. The server detects that the leases
2257     // are reserved for someone else.
2258     ASSERT_NO_THROW(client.doRenew());
2259 
2260     // For those leases, the first client should get 0 lifetimes.
2261     ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::1")));
2262     ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3001:0:0:10::"), 64));
2263 
2264     // The total number of leases should be 4 - two leases with zero lifetimes
2265     // and two leases with address and prefix from the dynamic pools, which
2266     // replace previously assigned leases. We don't care too much what those
2267     // leases are, though.
2268     EXPECT_EQ(4, client.getLeaseNum());
2269 
2270     // The second client renews and the server should be now able to assign
2271     // all reserved leases to this client.
2272     ASSERT_NO_THROW(client_.doRenew());
2273 
2274     // Client requests 4 leases, but there are additional two with zero
2275     // lifetimes to indicate that the client should not use the address
2276     // and prefix from the dynamic pools anymore.
2277     ASSERT_EQ(6, client_.getLeaseNum());
2278 
2279     // Check that the client has all reserved leases.
2280     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::2"),
2281                                            IAID(1)));
2282     EXPECT_TRUE(client_.hasLeaseForAddress(IOAddress("2001:db8:1::1"),
2283                                            IAID(2)));
2284 
2285     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:9::"), 64,
2286                                           IAID(3)));
2287     EXPECT_TRUE(client_.hasLeaseForPrefix(IOAddress("3001:0:0:10::"), 64,
2288                                           IAID(4)));
2289 }
2290 
2291 // This test verifies a scenario in which a client trying to renew a
2292 // lease is refused this lease because it has been reserved to another
2293 // client. The client is assigned another available lease from a
2294 // dynamic pool by reusing an expired lease.
TEST_F(HostTest,conflictResolutionReuseExpired)2295 TEST_F(HostTest, conflictResolutionReuseExpired) {
2296     Dhcp6Client client1;
2297 
2298     ASSERT_NO_THROW(configure(CONFIGS[6], *client1.getServer()));
2299 
2300     // First client performs 4-way exchange and obtains an address and
2301     // prefix indicated in hints.
2302     requestIA(client1, Hint(IAID(1), "2001:db8:1::1"));
2303     requestIA(client1, Hint(IAID(2), "3000::/120"));
2304 
2305     ASSERT_NO_THROW(client1.doSARR());
2306 
2307     // Make sure the client has obtained requested leases.
2308     ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::1"), IAID(1)));
2309     ASSERT_TRUE(client1.hasLeaseForPrefix(IOAddress("3000::"), 120));
2310 
2311     // Create another client which is assigned another lease.
2312     Dhcp6Client client2(client1.getServer());
2313 
2314     // Second client performs 4-way exchange and obtains an address and
2315     // prefix indicated in hints.
2316     requestIA(client2, Hint(IAID(1), "2001:db8:1::2"));
2317     requestIA(client2, Hint(IAID(2), "3000::100/120"));
2318 
2319     ASSERT_NO_THROW(client2.doSARR());
2320 
2321     // Make sure the client has obtained requested leases.
2322     ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::2"), IAID(1)));
2323     ASSERT_TRUE(client2.hasLeaseForPrefix(IOAddress("3000::100"), 120));
2324 
2325     // Fast forward time to simulate aging of leases. After that, both leases are
2326     // expired because their valid lifetime is 40s. The second argument indicates
2327     // that the leases should also be updated on the server.
2328     client1.fastFwdTime(60, true);
2329     client2.fastFwdTime(60, true);
2330 
2331     // Reconfigure the server, so as the address 2001:db8:1::2 and prefix
2332     // 3000::10/120 is now reserved for another client.
2333     ASSERT_NO_THROW(configure(CONFIGS[7], *client1.getServer()));
2334 
2335     client1.clearRequestedIAs();
2336     client2.clearRequestedIAs();
2337 
2338     // Try to renew the address of 2001:db8:1::2 and prefix 3000::100/120.
2339     ASSERT_NO_THROW(client2.doRenew());
2340 
2341     // The renewed address and prefix are now reserved for another client so
2342     // available leases  should be allocated instead.
2343     EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::1")));
2344     EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("3000::"), 120));
2345     // The previously allocated leases should now be returned with zero lifetimes.
2346     EXPECT_TRUE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::2")));
2347     EXPECT_TRUE(client2.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000::100"), 120));
2348 
2349     // We've had a bug in DHCPv6 server that reused lease (allocated previously to
2350     // a different client) was returned to the client reusing leases. This a big issue
2351     // because effectively a client reusing an expired lease would get this lease twice:
2352     // with non-zero lifetimes and the second time with zero lifetimes. This is seriously
2353     // confusing for the clients. This checks tha the bug has been eliminated.
2354     EXPECT_FALSE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::1")));
2355     EXPECT_FALSE(client2.hasLeaseWithZeroLifetimeForPrefix(IOAddress("3000::"), 120));
2356 }
2357 
2358 // Verifies fundamental Global vs Subnet host reservations for NA leases
TEST_F(HostTest,globalReservationsNA)2359 TEST_F(HostTest, globalReservationsNA) {
2360     Dhcp6Client client;
2361     ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[8], *client.getServer()));
2362 
2363     const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
2364         getCfgSubnets6()->getAll();
2365     ASSERT_EQ(2, subnets->size());
2366 
2367     {
2368         SCOPED_TRACE("Global HR by DUID with reserved address");
2369         client.setDUID("01:02:03:04");
2370         client.requestAddress(1234, IOAddress("::"));
2371         // Should get global reserved address and reserved host name
2372         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::1", "duid-host-fixed"));
2373     }
2374 
2375     {
2376         SCOPED_TRACE("Global HR by DUID with dynamic address");
2377         client.clearConfig();
2378         client.setDUID("01:02:03:05");
2379         client.requestAddress(1234, IOAddress("::"));
2380         // Should get dynamic address and reserved host name
2381         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::", "duid-host-dynamic"));
2382     }
2383 
2384     {
2385         SCOPED_TRACE("Global HR by HW Address with dynamic address");
2386         client.clearConfig();
2387         client.setDUID("33:44:55:66");
2388         client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee"));
2389         client.requestAddress(1234, IOAddress("::"));
2390         // Should get dynamic address and hardware host name
2391         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::1", "hw-host"));
2392     }
2393 
2394     {
2395         SCOPED_TRACE("Default subnet reservations flags excludes global reservations");
2396         client.clearConfig();
2397         client.setInterface("eth1");
2398         client.setDUID("01:02:03:04");
2399         client.requestAddress(1234, IOAddress("::"));
2400         // Should get dynamic address and no host name
2401         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::", ""));
2402     }
2403 
2404     {
2405         SCOPED_TRACE("Subnet reservation over global");
2406         client.clearConfig();
2407         client.setInterface("eth1");
2408         client.setDUID("01:02:03:05");
2409         client.requestAddress(1234, IOAddress("::"));
2410         // Should get dynamic address and host name
2411         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::1", "subnet-duid-host"));
2412     }
2413 
2414     {
2415         SCOPED_TRACE("Subnet reservation preferred over global");
2416         // Patch the second subnet to both global and in-subnet.
2417         Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
2418             getCfgSubnets6()->getSubnet(2);
2419         ASSERT_TRUE(subnet);
2420         subnet->setReservationsGlobal(true);
2421         subnet->setReservationsInSubnet(true);
2422         client.clearConfig();
2423         client.setInterface("eth1");
2424         client.setDUID("01:02:03:05");
2425         client.requestAddress(1234, IOAddress("::"));
2426         // Should get dynamic address and host name because it has preference
2427         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::1", "subnet-duid-host"));
2428     }
2429 }
2430 
2431 // Verifies fundamental Global vs Subnet host reservations for PD leases
TEST_F(HostTest,globalReservationsPD)2432 TEST_F(HostTest, globalReservationsPD) {
2433     Dhcp6Client client;
2434     ASSERT_NO_FATAL_FAILURE(configure(CONFIGS[9], *client.getServer()));
2435 
2436     const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
2437         getCfgSubnets6()->getAll();
2438     ASSERT_EQ(2, subnets->size());
2439 
2440     {
2441         SCOPED_TRACE("Global HR by DUID with reserved prefix");
2442         client.setDUID("01:02:03:04");
2443         client.requestPrefix(1);
2444         // Should get global reserved prefix and reserved host name
2445         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "4000::100", "duid-host-fixed"));
2446     }
2447 
2448     {
2449         SCOPED_TRACE("Global HR by DUID with dynamic prefix");
2450         client.clearConfig();
2451         client.setDUID("01:02:03:05");
2452         client.requestPrefix(1);
2453         // Should get dynamic prefix and reserved host name
2454         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3000::", "duid-host-dynamic"));
2455     }
2456 
2457     {
2458         SCOPED_TRACE("Default subnet reservations flags excludes global reservations");
2459         client.clearConfig();
2460         client.setInterface("eth1");
2461         client.setDUID("01:02:03:04");
2462         client.requestPrefix(1);
2463         // Should get dynamic prefix and no host name
2464         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::", ""));
2465     }
2466 
2467     {
2468         SCOPED_TRACE("Subnet reservation over global");
2469         client.clearConfig();
2470         client.setInterface("eth1");
2471         client.setDUID("01:02:03:05");
2472         client.requestPrefix(1);
2473         // Should get dynamic prefix and subnet reserved host name
2474         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::100", "subnet-duid-host"));
2475     }
2476 
2477     {
2478         SCOPED_TRACE("Subnet reservation preferred over global");
2479         // Patch the second subnet to both global and in-subnet.
2480         Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
2481             getCfgSubnets6()->getSubnet(2);
2482         ASSERT_TRUE(subnet);
2483         subnet->setReservationsGlobal(true);
2484         subnet->setReservationsInSubnet(true);
2485         client.clearConfig();
2486         client.setInterface("eth1");
2487         client.setDUID("01:02:03:05");
2488         client.requestPrefix(1);
2489         // Should get dynamic prefix and subnet reserved host name
2490         // because it has preference over the global reservation.
2491         ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::100", "subnet-duid-host"));
2492     }
2493 }
2494 
2495 // Verifies that client class specified in the global reservation
2496 // may be used to influence pool selection.
TEST_F(HostTest,clientClassGlobalPoolSelection)2497 TEST_F(HostTest, clientClassGlobalPoolSelection) {
2498     ASSERT_NO_FATAL_FAILURE(testGlobalClassSubnetPoolSelection(10));
2499 }
2500 
2501 // Verifies that client class specified in the global reservation
2502 // may be used to influence subnet selection within shared network.
TEST_F(HostTest,clientClassGlobalSubnetSelection)2503 TEST_F(HostTest, clientClassGlobalSubnetSelection) {
2504     ASSERT_NO_FATAL_FAILURE(testGlobalClassSubnetPoolSelection(11));
2505 }
2506 
2507 // Verifies that client class specified in the reservation may be
2508 // used to influence pool selection within a subnet.
TEST_F(HostTest,clientClassPoolSelection)2509 TEST_F(HostTest, clientClassPoolSelection) {
2510     ASSERT_NO_FATAL_FAILURE(testGlobalClassSubnetPoolSelection(12, "2001:db8:1::10",
2511                                                                "2001:db8:1::20"));
2512 }
2513 
2514 // Verifies that if the server is configured to allow for specifying
2515 // multiple reservations for the same IP address the first client
2516 // matching the reservation will be given this address. The second
2517 // client will be given a different lease.
TEST_F(HostTest,firstClientGetsReservedAddress)2518 TEST_F(HostTest, firstClientGetsReservedAddress) {
2519     // Create a client which has DUID matching the reservation.
2520     Dhcp6Client client1;
2521     client1.setDUID("01:02:03:04");
2522     ASSERT_NO_THROW(configure(CONFIGS[13], *client1.getServer()));
2523     // client1 performs 4-way exchange to get the reserved lease.
2524     requestIA(client1, Hint(IAID(1), "2001:db8:1::10"));
2525     ASSERT_NO_THROW(client1.doSARR());
2526 
2527     // Make sure the client has obtained reserved lease.
2528     ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2529 
2530     // Create another client that has a reservation for the same
2531     // IP address.
2532     Dhcp6Client client2(client1.getServer());
2533     client2.setDUID("01:02:03:05");
2534     requestIA(client2, Hint(IAID(1), "2001:db8:1::10"));
2535 
2536     // client2 performs 4-way exchange.
2537     ASSERT_NO_THROW(client2.doSARR());
2538 
2539     // Make sure the client didn't get the reserved lease. This lease has been
2540     // already taken by the client1.
2541     EXPECT_FALSE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2542 
2543     // Make sure the client2 got a lease from the configured pool.
2544     auto leases = client2.getLeasesByAddressRange(IOAddress("2001:db8:1::10"),
2545                                                   IOAddress("2001:db8:1::200"));
2546     EXPECT_EQ(1, leases.size());
2547 
2548     // Verify that the client1 can renew the lease.
2549     ASSERT_NO_THROW(client1.doRenew());
2550     EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2551 
2552     // The client2 should also renew the lease.
2553     ASSERT_NO_THROW(client2.doRenew());
2554     EXPECT_FALSE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2555     leases = client2.getLeasesByAddressRange(IOAddress("2001:db8:1::10"),
2556                                              IOAddress("2001:db8:1::200"));
2557     EXPECT_EQ(1, leases.size());
2558 
2559     // If the client1 releases the reserved lease, the client2 should acquire it.
2560     ASSERT_NO_THROW(client1.doRelease());
2561     ASSERT_NO_THROW(client2.doRenew());
2562     EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::15"), IAID(1)));
2563 }
2564 
2565 // Verifies that if the server is configured to allow for specifying
2566 // multiple reservations for the same delegated prefix the first client
2567 // matching the reservation will be given this prefix. The second
2568 // client will be given a different lease.
TEST_F(HostTest,firstClientGetsReservedPrefix)2569 TEST_F(HostTest, firstClientGetsReservedPrefix) {
2570     // Create a client which has DUID matching the reservation.
2571     Dhcp6Client client1;
2572     client1.setDUID("01:02:03:04");
2573     ASSERT_NO_THROW(configure(CONFIGS[14], *client1.getServer()));
2574     // client1 performs 4-way exchange to get the reserved lease.
2575     client1.requestPrefix(1);
2576     ASSERT_NO_THROW(client1.doSARR());
2577 
2578     // Make sure the client has obtained reserved lease.
2579     ASSERT_TRUE(client1.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2580 
2581     // Create another client that has a reservation for the same
2582     // IP address.
2583     Dhcp6Client client2(client1.getServer());
2584     client2.setDUID("01:02:03:05");
2585     client2.requestPrefix(1);
2586 
2587     // client2 performs 4-way exchange.
2588     ASSERT_NO_THROW(client2.doSARR());
2589 
2590     // Make sure the client didn't get the reserved lease. This lease has been
2591     // already taken by the client1.
2592     EXPECT_FALSE(client2.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2593 
2594     // Make sure the client2 got a lease from the configured pool.
2595     EXPECT_TRUE(client2.hasLeaseForPrefixPool(IOAddress("3000::"), 64, 112));
2596 
2597     // Verify that the client1 can renew the lease.
2598     ASSERT_NO_THROW(client1.doRenew());
2599     EXPECT_TRUE(client1.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2600 
2601     // The client2 should also renew the lease.
2602     ASSERT_NO_THROW(client2.doRenew());
2603     EXPECT_TRUE(client2.hasLeaseForPrefixPool(IOAddress("3000::"), 64, 112));
2604 
2605     // If the client1 releases the reserved lease, the client2 should acquire it.
2606     ASSERT_NO_THROW(client1.doRelease());
2607     ASSERT_NO_THROW(client2.doRenew());
2608     EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("3000::5a:0"), 112, IAID(1)));
2609 }
2610 
2611 /// This test verifies the case when two clients have reservations for
2612 /// the same IP address. The first client sends Solicit and is offered
2613 /// the reserved address. At the same time, the second client having
2614 /// the reservation for the same IP address performs 4-way exchange
2615 /// using the reserved address as a hint in Solicit.
2616 /// The client gets the lease for this address. This test verifies
2617 /// that the allocation engine correctly identifies that the second
2618 /// client has a reservation for this address.
TEST_F(HostTest,multipleClientsRace1)2619 TEST_F(HostTest, multipleClientsRace1) {
2620     ASSERT_NO_FATAL_FAILURE(testMultipleClientsRace("01:02:03:04", "01:02:03:05"));
2621 }
2622 
2623 // This is a second variant of the multipleClientsRace1. The test is almost
2624 // the same but the client matching the second reservation sends Solicit
2625 // first and then the client having the first reservation performs 4-way
2626 // exchange. This is to ensure that the order in which reservations are
2627 // defined does not matter.
TEST_F(HostTest,multipleClientsRace2)2628 TEST_F(HostTest, multipleClientsRace2) {
2629     ASSERT_NO_FATAL_FAILURE(testMultipleClientsRace("01:02:03:05", "01:02:03:04"));
2630 }
2631 
2632 } // end of anonymous namespace
2633