1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright (C) 2014 Intel Corporation. All rights reserved.
6 #include <net/ethernet.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
13 #include "sd-dhcp6-client.h"
16 #include "dhcp6-internal.h"
17 #include "dhcp6-lease-internal.h"
18 #include "dhcp6-protocol.h"
21 #include "socket-util.h"
24 static struct ether_addr mac_addr
= {
25 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
28 static bool verbose
= true;
30 static sd_event_source
*hangcheck
;
31 static int test_dhcp_fd
[2];
32 static int test_index
= 42;
33 static int test_client_message_num
;
34 static be32_t test_iaid
= 0;
35 static uint8_t test_duid
[14] = { };
37 static int test_client_basic(sd_event
*e
) {
38 sd_dhcp6_client
*client
;
41 printf("* %s\n", __FUNCTION__
);
43 assert_se(sd_dhcp6_client_new(&client
) >= 0);
46 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
48 assert_se(sd_dhcp6_client_set_ifindex(client
, 15) == 0);
49 assert_se(sd_dhcp6_client_set_ifindex(client
, -42) == -EINVAL
);
50 assert_se(sd_dhcp6_client_set_ifindex(client
, -1) == 0);
51 assert_se(sd_dhcp6_client_set_ifindex(client
, 42) >= 0);
53 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
57 assert_se(sd_dhcp6_client_set_fqdn(client
, "host") == 1);
58 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.domain") == 1);
59 assert_se(sd_dhcp6_client_set_fqdn(client
, NULL
) == 1);
60 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host") == -EINVAL
);
61 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host.domain") == -EINVAL
);
63 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CLIENTID
) == -EINVAL
);
64 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EEXIST
);
65 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
) == -EEXIST
);
66 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVERS
) == -EEXIST
);
67 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN_LIST
) == -EEXIST
);
68 assert_se(sd_dhcp6_client_set_request_option(client
, 10) == -EINVAL
);
70 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, NULL
) >= 0);
72 assert_se(sd_dhcp6_client_detach_event(client
) >= 0);
73 assert_se(!sd_dhcp6_client_unref(client
));
78 static int test_option(sd_event
*e
) {
81 0x00, SD_DHCP6_OPTION_ORO
, 0x00, 0x07,
82 'A', 'B', 'C', 'D', 'E', 'F', 'G',
83 0x00, SD_DHCP6_OPTION_VENDOR_CLASS
, 0x00, 0x09,
84 '1', '2', '3', '4', '5', '6', '7', '8', '9',
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 uint8_t *optval
, *buf
, *out
;
97 size_t zero
= 0, pos
= 3;
98 size_t buflen
= sizeof(packet
), outlen
= sizeof(result
);
101 printf("* %s\n", __FUNCTION__
);
103 assert_se(buflen
== outlen
);
105 assert_se(dhcp6_option_parse(&buf
, &zero
, &optcode
, &optlen
,
106 &optval
) == -ENOMSG
);
113 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
116 assert_se(buf
== &packet
[pos
]);
117 assert_se(optcode
== SD_DHCP6_OPTION_ORO
);
118 assert_se(optlen
== 7);
119 assert_se(buflen
+ pos
== sizeof(packet
));
121 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
123 assert_se(out
== &result
[pos
]);
124 assert_se(*out
== 0x00);
126 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
129 assert_se(buf
== &packet
[pos
]);
130 assert_se(optcode
== SD_DHCP6_OPTION_VENDOR_CLASS
);
131 assert_se(optlen
== 9);
132 assert_se(buflen
+ pos
== sizeof(packet
));
134 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
136 assert_se(out
== &result
[pos
]);
137 assert_se(*out
== 'B');
139 assert_se(memcmp(packet
, result
, sizeof(packet
)) == 0);
144 static int test_option_status(sd_event
*e
) {
145 uint8_t option1
[] = {
147 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
148 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
150 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
152 static const uint8_t option2
[] = {
154 0x00, 0x03, 0x00, 0x2e, 0x1a, 0x1d, 0x1a, 0x1d,
155 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
157 0x00, 0x05, 0x00, 0x1e,
158 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
159 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
160 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
162 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
164 static const uint8_t option3
[] = {
166 0x00, 0x03, 0x00, 0x34, 0x1a, 0x1d, 0x1a, 0x1d,
167 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
169 0x00, 0x05, 0x00, 0x24,
170 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
171 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
172 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
174 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
177 static const uint8_t option4
[] = {
179 0x00, 0x19, 0x00, 0x2f, 0x1a, 0x1d, 0x1a, 0x1d,
180 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
182 0x00, 0x1a, 0x00, 0x1f,
183 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
184 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
185 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
190 static const uint8_t option5
[] = {
192 0x00, 0x19, 0x00, 0x52, 0x1a, 0x1d, 0x1a, 0x1d,
193 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
194 /* IA PD Prefix #1 */
195 0x00, 0x1a, 0x00, 0x1f,
196 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
197 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
198 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
202 /* IA PD Prefix #2 */
203 0x00, 0x1a, 0x00, 0x1f,
204 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
205 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l
, 0xd0,
206 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
215 printf("* %s\n", __FUNCTION__
);
218 option
= (DHCP6Option
*)option1
;
219 assert_se(sizeof(option1
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
221 r
= dhcp6_option_parse_ia(option
, &ia
);
222 assert_se(r
== -EINVAL
);
223 assert_se(ia
.addresses
== NULL
);
225 option
->len
= htobe16(17);
226 r
= dhcp6_option_parse_ia(option
, &ia
);
227 assert_se(r
== -ENOBUFS
);
228 assert_se(ia
.addresses
== NULL
);
230 option
->len
= htobe16(sizeof(DHCP6Option
));
231 r
= dhcp6_option_parse_ia(option
, &ia
);
232 assert_se(r
== -ENOBUFS
);
233 assert_se(ia
.addresses
== NULL
);
236 option
= (DHCP6Option
*)option2
;
237 assert_se(sizeof(option2
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
239 r
= dhcp6_option_parse_ia(option
, &ia
);
241 assert_se(ia
.addresses
== NULL
);
244 option
= (DHCP6Option
*)option3
;
245 assert_se(sizeof(option3
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
247 r
= dhcp6_option_parse_ia(option
, &ia
);
249 assert_se(ia
.addresses
!= NULL
);
250 dhcp6_lease_free_ia(&ia
);
253 option
= (DHCP6Option
*)option4
;
254 assert_se(sizeof(option4
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
256 r
= dhcp6_option_parse_ia(option
, &pd
);
258 assert_se(pd
.addresses
!= NULL
);
259 assert_se(memcmp(&pd
.ia_pd
.id
, &option4
[4], 4) == 0);
260 assert_se(memcmp(&pd
.ia_pd
.lifetime_t1
, &option4
[8], 4) == 0);
261 assert_se(memcmp(&pd
.ia_pd
.lifetime_t2
, &option4
[12], 4) == 0);
262 dhcp6_lease_free_ia(&pd
);
265 option
= (DHCP6Option
*)option5
;
266 assert_se(sizeof(option5
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
268 r
= dhcp6_option_parse_ia(option
, &pd
);
270 assert_se(pd
.addresses
!= NULL
);
271 dhcp6_lease_free_ia(&pd
);
276 static uint8_t msg_advertise
[198] = {
277 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
278 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
279 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
280 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
281 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
282 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
283 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
284 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
285 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
286 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
287 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
288 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
289 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
290 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
291 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
292 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
293 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
295 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
296 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
297 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
299 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
300 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
301 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
304 static uint8_t msg_reply
[173] = {
305 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
306 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
307 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
308 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
309 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
310 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
311 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
312 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
313 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
314 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
315 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
316 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
317 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
318 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
319 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
320 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
321 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
323 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
324 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
325 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x01
329 static uint8_t fqdn_wire
[16] = {
330 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
331 0x05, 'i', 'n', 't', 'r', 'a', 0x00
334 static int test_advertise_option(sd_event
*e
) {
335 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
336 DHCP6Message
*advertise
= (DHCP6Message
*)msg_advertise
;
337 size_t len
= sizeof(msg_advertise
) - sizeof(DHCP6Message
), pos
= 0;
339 uint8_t preference
= 255;
340 struct in6_addr addr
;
341 uint32_t lt_pref
, lt_valid
;
344 bool opt_clientid
= false;
345 struct in6_addr
*addrs
;
349 printf("* %s\n", __FUNCTION__
);
351 assert_se(len
>= sizeof(DHCP6Message
));
353 assert_se(dhcp6_lease_new(&lease
) >= 0);
355 assert_se(advertise
->type
== DHCP6_ADVERTISE
);
356 assert_se((be32toh(advertise
->transaction_id
) & 0x00ffffff) ==
360 DHCP6Option
*option
= (DHCP6Option
*)&advertise
->options
[pos
];
361 const uint16_t optcode
= be16toh(option
->code
);
362 const uint16_t optlen
= be16toh(option
->len
);
363 uint8_t *optval
= option
->data
;
366 case SD_DHCP6_OPTION_CLIENTID
:
367 assert_se(optlen
== 14);
372 case SD_DHCP6_OPTION_IA_NA
:
373 assert_se(optlen
== 94);
374 assert_se(!memcmp(optval
, &msg_advertise
[26], optlen
));
376 val
= htobe32(0x0ecfa37d);
377 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
380 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
383 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
385 assert_se(dhcp6_option_parse_ia(option
, &lease
->ia
) >= 0);
389 case SD_DHCP6_OPTION_SERVERID
:
390 assert_se(optlen
== 14);
391 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
393 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
397 case SD_DHCP6_OPTION_PREFERENCE
:
398 assert_se(optlen
== 1);
401 assert_se(dhcp6_lease_set_preference(lease
,
405 case SD_DHCP6_OPTION_ELAPSED_TIME
:
406 assert_se(optlen
== 2);
410 case SD_DHCP6_OPTION_DNS_SERVERS
:
411 assert_se(optlen
== 16);
412 assert_se(dhcp6_lease_set_dns(lease
, optval
,
416 case SD_DHCP6_OPTION_DOMAIN_LIST
:
417 assert_se(optlen
== 11);
418 assert_se(dhcp6_lease_set_domains(lease
, optval
,
422 case SD_DHCP6_OPTION_SNTP_SERVERS
:
423 assert_se(optlen
== 16);
424 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
432 pos
+= sizeof(*option
) + optlen
;
435 assert_se(pos
== len
);
436 assert_se(opt_clientid
);
438 sd_dhcp6_lease_reset_address_iter(lease
);
439 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
441 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
442 assert_se(lt_pref
== 150);
443 assert_se(lt_valid
== 180);
444 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
445 <_valid
) == -ENOMSG
);
447 sd_dhcp6_lease_reset_address_iter(lease
);
448 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
450 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
451 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
452 <_valid
) == -ENOMSG
);
453 sd_dhcp6_lease_reset_address_iter(lease
);
454 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
456 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
457 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
458 <_valid
) == -ENOMSG
);
460 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
461 assert_se(len
== 14);
462 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
464 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
465 assert_se(preference
== 0);
467 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
469 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
471 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
473 assert_se(!strcmp("lab.intra", domains
[0]));
474 assert_se(domains
[1] == NULL
);
476 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
478 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
483 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
484 assert_not_reached("Test case should have completed in 2 seconds");
489 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
491 sd_event
*e
= userdata
;
492 sd_dhcp6_lease
*lease
;
493 struct in6_addr
*addrs
;
497 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
499 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
501 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
502 assert_se(!strcmp("lab.intra", domains
[0]));
503 assert_se(domains
[1] == NULL
);
505 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
506 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
508 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
509 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
511 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
514 printf(" got DHCPv6 event %d\n", event
);
519 static int test_client_send_reply(DHCP6Message
*request
) {
522 reply
.transaction_id
= request
->transaction_id
;
523 reply
.type
= DHCP6_REPLY
;
525 memcpy(msg_reply
, &reply
.transaction_id
, 4);
527 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
529 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
531 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
532 == sizeof(msg_reply
));
537 static int test_client_verify_request(DHCP6Message
*request
, size_t len
) {
538 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
540 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
541 found_elapsed_time
= false, found_fqdn
= false;
542 struct in6_addr addr
;
544 uint32_t lt_pref
, lt_valid
;
546 assert_se(request
->type
== DHCP6_REQUEST
);
548 assert_se(dhcp6_lease_new(&lease
) >= 0);
550 len
-= sizeof(DHCP6Message
);
553 DHCP6Option
*option
= (DHCP6Option
*)&request
->options
[pos
];
554 uint16_t optcode
= be16toh(option
->code
);
555 uint16_t optlen
= be16toh(option
->len
);
556 uint8_t *optval
= option
->data
;
559 case SD_DHCP6_OPTION_CLIENTID
:
560 assert_se(!found_clientid
);
561 found_clientid
= true;
563 assert_se(!memcmp(optval
, &test_duid
,
568 case SD_DHCP6_OPTION_IA_NA
:
569 assert_se(!found_iana
);
572 assert_se(optlen
== 40);
573 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
576 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
579 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
581 assert_se(!dhcp6_option_parse_ia(option
, &lease
->ia
));
585 case SD_DHCP6_OPTION_SERVERID
:
586 assert_se(!found_serverid
);
587 found_serverid
= true;
589 assert_se(optlen
== 14);
590 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
594 case SD_DHCP6_OPTION_ELAPSED_TIME
:
595 assert_se(!found_elapsed_time
);
596 found_elapsed_time
= true;
598 assert_se(optlen
== 2);
601 case SD_DHCP6_OPTION_FQDN
:
602 assert_se(!found_fqdn
);
605 assert_se(optlen
== 17);
607 assert_se(optval
[0] == 0x01);
608 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
612 pos
+= sizeof(*option
) + optlen
;
615 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
618 sd_dhcp6_lease_reset_address_iter(lease
);
619 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
621 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
622 assert_se(lt_pref
== 150);
623 assert_se(lt_valid
== 180);
625 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
626 <_valid
) == -ENOMSG
);
631 static int test_client_send_advertise(DHCP6Message
*solicit
) {
632 DHCP6Message advertise
;
634 advertise
.transaction_id
= solicit
->transaction_id
;
635 advertise
.type
= DHCP6_ADVERTISE
;
637 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
639 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
641 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
643 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
644 == sizeof(msg_advertise
));
649 static int test_client_verify_solicit(DHCP6Message
*solicit
, size_t len
) {
650 bool found_clientid
= false, found_iana
= false,
651 found_elapsed_time
= false, found_fqdn
= false;
654 assert_se(solicit
->type
== DHCP6_SOLICIT
);
656 len
-= sizeof(DHCP6Message
);
659 DHCP6Option
*option
= (DHCP6Option
*)&solicit
->options
[pos
];
660 uint16_t optcode
= be16toh(option
->code
);
661 uint16_t optlen
= be16toh(option
->len
);
662 uint8_t *optval
= option
->data
;
665 case SD_DHCP6_OPTION_CLIENTID
:
666 assert_se(!found_clientid
);
667 found_clientid
= true;
669 assert_se(optlen
== sizeof(test_duid
));
670 memcpy(&test_duid
, optval
, sizeof(test_duid
));
674 case SD_DHCP6_OPTION_IA_NA
:
675 assert_se(!found_iana
);
678 assert_se(optlen
== 12);
680 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
684 case SD_DHCP6_OPTION_ELAPSED_TIME
:
685 assert_se(!found_elapsed_time
);
686 found_elapsed_time
= true;
688 assert_se(optlen
== 2);
692 case SD_DHCP6_OPTION_FQDN
:
693 assert_se(!found_fqdn
);
696 assert_se(optlen
== 17);
698 assert_se(optval
[0] == 0x01);
699 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
704 pos
+= sizeof(*option
) + optlen
;
707 assert_se(pos
== len
);
708 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
713 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
715 sd_event
*e
= userdata
;
716 sd_dhcp6_lease
*lease
;
717 struct in6_addr
*addrs
;
718 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
722 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
724 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
726 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
727 assert_se(!strcmp("lab.intra", domains
[0]));
728 assert_se(domains
[1] == NULL
);
730 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
731 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
733 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
734 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
737 printf(" got DHCPv6 event %d\n", event
);
739 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
740 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
741 assert_se(sd_dhcp6_client_stop(client
) >= 0);
742 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
744 assert_se(sd_dhcp6_client_set_callback(client
,
745 test_client_solicit_cb
, e
) >= 0);
747 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
749 assert_se(sd_dhcp6_client_start(client
) >= 0);
753 static int test_client_verify_information_request(DHCP6Message
*information_request
,
756 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
758 bool found_clientid
= false, found_elapsed_time
= false;
759 struct in6_addr addr
;
760 uint32_t lt_pref
, lt_valid
;
762 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
764 assert_se(dhcp6_lease_new(&lease
) >= 0);
766 len
-= sizeof(DHCP6Message
);
769 DHCP6Option
*option
= (DHCP6Option
*)&information_request
->options
[pos
];
770 uint16_t optcode
= be16toh(option
->code
);
771 uint16_t optlen
= be16toh(option
->len
);
772 uint8_t *optval
= option
->data
;
775 case SD_DHCP6_OPTION_CLIENTID
:
776 assert_se(!found_clientid
);
777 found_clientid
= true;
779 assert_se(optlen
== sizeof(test_duid
));
780 memcpy(&test_duid
, optval
, sizeof(test_duid
));
784 case SD_DHCP6_OPTION_IA_NA
:
785 assert_not_reached("IA TA option must not be present");
789 case SD_DHCP6_OPTION_SERVERID
:
790 assert_not_reached("Server ID option must not be present");
794 case SD_DHCP6_OPTION_ELAPSED_TIME
:
795 assert_se(!found_elapsed_time
);
796 found_elapsed_time
= true;
798 assert_se(optlen
== 2);
803 pos
+= sizeof(*option
) + optlen
;
806 assert_se(pos
== len
);
807 assert_se(found_clientid
&& found_elapsed_time
);
809 sd_dhcp6_lease_reset_address_iter(lease
);
811 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
812 <_valid
) == -ENOMSG
);
817 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
818 const void *packet
, size_t len
) {
819 struct in6_addr mcast
=
820 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
821 DHCP6Message
*message
;
823 assert_se(s
== test_dhcp_fd
[0]);
824 assert_se(server_address
);
826 assert_se(len
> sizeof(DHCP6Message
) + 4);
828 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
830 message
= (DHCP6Message
*)packet
;
832 assert_se(message
->transaction_id
& 0x00ffffff);
834 if (test_client_message_num
== 0) {
835 test_client_verify_information_request(message
, len
);
836 test_client_send_reply(message
);
837 test_client_message_num
++;
838 } else if (test_client_message_num
== 1) {
839 test_client_verify_solicit(message
, len
);
840 test_client_send_advertise(message
);
841 test_client_message_num
++;
842 } else if (test_client_message_num
== 2) {
843 test_client_verify_request(message
, len
);
844 test_client_send_reply(message
);
845 test_client_message_num
++;
851 int dhcp6_network_bind_udp_socket(int index
, struct in6_addr
*local_address
) {
852 assert_se(index
== test_index
);
854 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, test_dhcp_fd
) < 0)
857 return test_dhcp_fd
[0];
860 static int test_client_solicit(sd_event
*e
) {
861 sd_dhcp6_client
*client
;
862 usec_t time_now
= now(clock_boottime_or_monotonic());
863 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
867 printf("* %s\n", __FUNCTION__
);
869 assert_se(sd_dhcp6_client_new(&client
) >= 0);
872 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
874 assert_se(sd_dhcp6_client_set_ifindex(client
, test_index
) == 0);
875 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
878 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
880 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
881 assert_se(val
== false);
882 assert_se(sd_dhcp6_client_set_information_request(client
, true) >= 0);
883 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
884 assert_se(val
== true);
886 assert_se(sd_dhcp6_client_set_callback(client
,
887 test_client_information_cb
, e
) >= 0);
889 assert_se(sd_event_add_time(e
, &hangcheck
, clock_boottime_or_monotonic(),
890 time_now
+ 2 * USEC_PER_SEC
, 0,
891 test_hangcheck
, NULL
) >= 0);
893 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
895 assert_se(sd_dhcp6_client_start(client
) >= 0);
899 hangcheck
= sd_event_source_unref(hangcheck
);
901 assert_se(!sd_dhcp6_client_unref(client
));
903 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
908 int main(int argc
, char *argv
[]) {
909 _cleanup_(sd_event_unrefp
) sd_event
*e
;
911 assert_se(sd_event_new(&e
) >= 0);
913 log_set_max_level(LOG_DEBUG
);
914 log_parse_environment();
917 test_client_basic(e
);
919 test_option_status(e
);
920 test_advertise_option(e
);
921 test_client_solicit(e
);