1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 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"
26 static struct ether_addr mac_addr
= {
27 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
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 log_debug("/* %s */", __func__
);
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_information_request(client
, 1) >= 0);
72 assert_se(sd_dhcp6_client_get_information_request(client
, &v
) >= 0);
74 assert_se(sd_dhcp6_client_set_information_request(client
, 0) >= 0);
76 assert_se(sd_dhcp6_client_get_information_request(client
, &v
) >= 0);
80 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
83 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
84 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
87 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
88 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
91 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
92 assert_se(sd_dhcp6_client_set_prefix_delegation(client
, 1) >= 0);
94 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
97 assert_se(sd_dhcp6_client_get_prefix_delegation(client
, &v
) >= 0);
100 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, NULL
) >= 0);
102 assert_se(sd_dhcp6_client_detach_event(client
) >= 0);
103 assert_se(!sd_dhcp6_client_unref(client
));
108 static int test_option(sd_event
*e
) {
111 0x00, SD_DHCP6_OPTION_ORO
, 0x00, 0x07,
112 'A', 'B', 'C', 'D', 'E', 'F', 'G',
113 0x00, SD_DHCP6_OPTION_VENDOR_CLASS
, 0x00, 0x09,
114 '1', '2', '3', '4', '5', '6', '7', '8', '9',
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 uint8_t *optval
, *buf
, *out
;
127 size_t zero
= 0, pos
= 3;
128 size_t buflen
= sizeof(packet
), outlen
= sizeof(result
);
130 log_debug("/* %s */", __func__
);
132 assert_se(buflen
== outlen
);
134 assert_se(dhcp6_option_parse(&buf
, &zero
, &optcode
, &optlen
,
135 &optval
) == -ENOMSG
);
142 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
145 assert_se(buf
== &packet
[pos
]);
146 assert_se(optcode
== SD_DHCP6_OPTION_ORO
);
147 assert_se(optlen
== 7);
148 assert_se(buflen
+ pos
== sizeof(packet
));
150 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
152 assert_se(out
== &result
[pos
]);
153 assert_se(*out
== 0x00);
155 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
158 assert_se(buf
== &packet
[pos
]);
159 assert_se(optcode
== SD_DHCP6_OPTION_VENDOR_CLASS
);
160 assert_se(optlen
== 9);
161 assert_se(buflen
+ pos
== sizeof(packet
));
163 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
165 assert_se(out
== &result
[pos
]);
166 assert_se(*out
== 'B');
168 assert_se(memcmp(packet
, result
, sizeof(packet
)) == 0);
173 static int test_option_status(sd_event
*e
) {
174 uint8_t option1
[] = {
176 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
177 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
179 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
181 static const uint8_t option2
[] = {
183 0x00, 0x03, 0x00, 0x2e, 0x1a, 0x1d, 0x1a, 0x1d,
184 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
186 0x00, 0x05, 0x00, 0x1e,
187 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
188 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
189 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
191 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
193 static const uint8_t option3
[] = {
195 0x00, 0x03, 0x00, 0x34, 0x1a, 0x1d, 0x1a, 0x1d,
196 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
198 0x00, 0x05, 0x00, 0x24,
199 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
200 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
201 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
203 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
206 static const uint8_t option4
[] = {
208 0x00, 0x19, 0x00, 0x2f, 0x1a, 0x1d, 0x1a, 0x1d,
209 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
211 0x00, 0x1a, 0x00, 0x1f,
212 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
213 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
214 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
219 static const uint8_t option5
[] = {
221 0x00, 0x19, 0x00, 0x52, 0x1a, 0x1d, 0x1a, 0x1d,
222 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
223 /* IA PD Prefix #1 */
224 0x00, 0x1a, 0x00, 0x1f,
225 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
226 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
227 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
231 /* IA PD Prefix #2 */
232 0x00, 0x1a, 0x00, 0x1f,
233 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
234 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l
, 0xd0,
235 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
243 log_debug("/* %s */", __func__
);
246 option
= (DHCP6Option
*)option1
;
247 assert_se(sizeof(option1
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
249 r
= dhcp6_option_parse_ia(option
, &ia
);
250 assert_se(r
== -EINVAL
);
251 assert_se(ia
.addresses
== NULL
);
253 option
->len
= htobe16(17);
254 r
= dhcp6_option_parse_ia(option
, &ia
);
255 assert_se(r
== -ENOBUFS
);
256 assert_se(ia
.addresses
== NULL
);
258 option
->len
= htobe16(sizeof(DHCP6Option
));
259 r
= dhcp6_option_parse_ia(option
, &ia
);
260 assert_se(r
== -ENOBUFS
);
261 assert_se(ia
.addresses
== NULL
);
264 option
= (DHCP6Option
*)option2
;
265 assert_se(sizeof(option2
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
267 r
= dhcp6_option_parse_ia(option
, &ia
);
269 assert_se(ia
.addresses
== NULL
);
272 option
= (DHCP6Option
*)option3
;
273 assert_se(sizeof(option3
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
275 r
= dhcp6_option_parse_ia(option
, &ia
);
277 assert_se(ia
.addresses
!= NULL
);
278 dhcp6_lease_free_ia(&ia
);
281 option
= (DHCP6Option
*)option4
;
282 assert_se(sizeof(option4
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
284 r
= dhcp6_option_parse_ia(option
, &pd
);
286 assert_se(pd
.addresses
!= NULL
);
287 assert_se(memcmp(&pd
.ia_pd
.id
, &option4
[4], 4) == 0);
288 assert_se(memcmp(&pd
.ia_pd
.lifetime_t1
, &option4
[8], 4) == 0);
289 assert_se(memcmp(&pd
.ia_pd
.lifetime_t2
, &option4
[12], 4) == 0);
290 dhcp6_lease_free_ia(&pd
);
293 option
= (DHCP6Option
*)option5
;
294 assert_se(sizeof(option5
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
296 r
= dhcp6_option_parse_ia(option
, &pd
);
298 assert_se(pd
.addresses
!= NULL
);
299 dhcp6_lease_free_ia(&pd
);
304 static uint8_t msg_advertise
[198] = {
305 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
306 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
307 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
308 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
309 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
310 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
311 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
312 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
313 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
314 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
315 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
316 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
317 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
318 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
319 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
320 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
321 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
323 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
324 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
325 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
327 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
328 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
329 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
332 static uint8_t msg_reply
[173] = {
333 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
334 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
335 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
336 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
337 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
338 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
339 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
340 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
341 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
342 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
343 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
344 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
345 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
346 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
347 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
348 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
349 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
351 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
352 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
353 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x01
357 static uint8_t fqdn_wire
[16] = {
358 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
359 0x05, 'i', 'n', 't', 'r', 'a', 0x00
362 static int test_advertise_option(sd_event
*e
) {
363 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
364 DHCP6Message
*advertise
= (DHCP6Message
*)msg_advertise
;
365 size_t len
= sizeof(msg_advertise
) - sizeof(DHCP6Message
), pos
= 0;
367 uint8_t preference
= 255;
368 struct in6_addr addr
;
369 uint32_t lt_pref
, lt_valid
;
372 bool opt_clientid
= false;
373 struct in6_addr
*addrs
;
376 log_debug("/* %s */", __func__
);
378 assert_se(len
>= sizeof(DHCP6Message
));
380 assert_se(dhcp6_lease_new(&lease
) >= 0);
382 assert_se(advertise
->type
== DHCP6_ADVERTISE
);
383 assert_se((be32toh(advertise
->transaction_id
) & 0x00ffffff) ==
387 DHCP6Option
*option
= (DHCP6Option
*)&advertise
->options
[pos
];
388 const uint16_t optcode
= be16toh(option
->code
);
389 const uint16_t optlen
= be16toh(option
->len
);
390 uint8_t *optval
= option
->data
;
393 case SD_DHCP6_OPTION_CLIENTID
:
394 assert_se(optlen
== 14);
399 case SD_DHCP6_OPTION_IA_NA
:
400 assert_se(optlen
== 94);
401 assert_se(!memcmp(optval
, &msg_advertise
[26], optlen
));
403 val
= htobe32(0x0ecfa37d);
404 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
407 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
410 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
412 assert_se(dhcp6_option_parse_ia(option
, &lease
->ia
) >= 0);
416 case SD_DHCP6_OPTION_SERVERID
:
417 assert_se(optlen
== 14);
418 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
420 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
424 case SD_DHCP6_OPTION_PREFERENCE
:
425 assert_se(optlen
== 1);
428 assert_se(dhcp6_lease_set_preference(lease
,
432 case SD_DHCP6_OPTION_ELAPSED_TIME
:
433 assert_se(optlen
== 2);
437 case SD_DHCP6_OPTION_DNS_SERVERS
:
438 assert_se(optlen
== 16);
439 assert_se(dhcp6_lease_set_dns(lease
, optval
,
443 case SD_DHCP6_OPTION_DOMAIN_LIST
:
444 assert_se(optlen
== 11);
445 assert_se(dhcp6_lease_set_domains(lease
, optval
,
449 case SD_DHCP6_OPTION_SNTP_SERVERS
:
450 assert_se(optlen
== 16);
451 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
459 pos
+= sizeof(*option
) + optlen
;
462 assert_se(pos
== len
);
463 assert_se(opt_clientid
);
465 sd_dhcp6_lease_reset_address_iter(lease
);
466 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
468 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
469 assert_se(lt_pref
== 150);
470 assert_se(lt_valid
== 180);
471 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
472 <_valid
) == -ENOMSG
);
474 sd_dhcp6_lease_reset_address_iter(lease
);
475 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
477 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
478 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
479 <_valid
) == -ENOMSG
);
480 sd_dhcp6_lease_reset_address_iter(lease
);
481 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
483 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
484 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
485 <_valid
) == -ENOMSG
);
487 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
488 assert_se(len
== 14);
489 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
491 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
492 assert_se(preference
== 0);
494 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
496 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
498 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
500 assert_se(!strcmp("lab.intra", domains
[0]));
501 assert_se(domains
[1] == NULL
);
503 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
505 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
510 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
511 assert_not_reached("Test case should have completed in 2 seconds");
516 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
518 sd_event
*e
= userdata
;
519 sd_dhcp6_lease
*lease
;
520 struct in6_addr
*addrs
;
523 log_debug("/* %s */", __func__
);
526 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
528 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
530 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
531 assert_se(!strcmp("lab.intra", domains
[0]));
532 assert_se(domains
[1] == NULL
);
534 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
535 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
537 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
538 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
540 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
545 static int test_client_send_reply(DHCP6Message
*request
) {
548 reply
.transaction_id
= request
->transaction_id
;
549 reply
.type
= DHCP6_REPLY
;
551 memcpy(msg_reply
, &reply
.transaction_id
, 4);
553 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
555 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
557 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
558 == sizeof(msg_reply
));
563 static int test_client_verify_request(DHCP6Message
*request
, size_t len
) {
564 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
566 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
567 found_elapsed_time
= false, found_fqdn
= false;
568 struct in6_addr addr
;
570 uint32_t lt_pref
, lt_valid
;
572 log_debug("/* %s */", __func__
);
574 assert_se(request
->type
== DHCP6_REQUEST
);
575 assert_se(dhcp6_lease_new(&lease
) >= 0);
577 len
-= sizeof(DHCP6Message
);
580 DHCP6Option
*option
= (DHCP6Option
*)&request
->options
[pos
];
581 uint16_t optcode
= be16toh(option
->code
);
582 uint16_t optlen
= be16toh(option
->len
);
583 uint8_t *optval
= option
->data
;
586 case SD_DHCP6_OPTION_CLIENTID
:
587 assert_se(!found_clientid
);
588 found_clientid
= true;
590 assert_se(!memcmp(optval
, &test_duid
,
595 case SD_DHCP6_OPTION_IA_NA
:
596 assert_se(!found_iana
);
599 assert_se(optlen
== 40);
600 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
603 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
606 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
608 assert_se(!dhcp6_option_parse_ia(option
, &lease
->ia
));
612 case SD_DHCP6_OPTION_SERVERID
:
613 assert_se(!found_serverid
);
614 found_serverid
= true;
616 assert_se(optlen
== 14);
617 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
621 case SD_DHCP6_OPTION_ELAPSED_TIME
:
622 assert_se(!found_elapsed_time
);
623 found_elapsed_time
= true;
625 assert_se(optlen
== 2);
628 case SD_DHCP6_OPTION_FQDN
:
629 assert_se(!found_fqdn
);
632 assert_se(optlen
== 17);
634 assert_se(optval
[0] == 0x01);
635 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
639 pos
+= sizeof(*option
) + optlen
;
642 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
645 sd_dhcp6_lease_reset_address_iter(lease
);
646 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
648 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
649 assert_se(lt_pref
== 150);
650 assert_se(lt_valid
== 180);
652 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
653 <_valid
) == -ENOMSG
);
658 static int test_client_send_advertise(DHCP6Message
*solicit
) {
659 DHCP6Message advertise
;
661 advertise
.transaction_id
= solicit
->transaction_id
;
662 advertise
.type
= DHCP6_ADVERTISE
;
664 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
666 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
668 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
670 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
671 == sizeof(msg_advertise
));
676 static int test_client_verify_solicit(DHCP6Message
*solicit
, size_t len
) {
677 bool found_clientid
= false, found_iana
= false,
678 found_elapsed_time
= false, found_fqdn
= false;
681 log_debug("/* %s */", __func__
);
683 assert_se(solicit
->type
== DHCP6_SOLICIT
);
685 len
-= sizeof(DHCP6Message
);
688 DHCP6Option
*option
= (DHCP6Option
*)&solicit
->options
[pos
];
689 uint16_t optcode
= be16toh(option
->code
);
690 uint16_t optlen
= be16toh(option
->len
);
691 uint8_t *optval
= option
->data
;
694 case SD_DHCP6_OPTION_CLIENTID
:
695 assert_se(!found_clientid
);
696 found_clientid
= true;
698 assert_se(optlen
== sizeof(test_duid
));
699 memcpy(&test_duid
, optval
, sizeof(test_duid
));
703 case SD_DHCP6_OPTION_IA_NA
:
704 assert_se(!found_iana
);
707 assert_se(optlen
== 12);
709 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
713 case SD_DHCP6_OPTION_ELAPSED_TIME
:
714 assert_se(!found_elapsed_time
);
715 found_elapsed_time
= true;
717 assert_se(optlen
== 2);
721 case SD_DHCP6_OPTION_FQDN
:
722 assert_se(!found_fqdn
);
725 assert_se(optlen
== 17);
727 assert_se(optval
[0] == 0x01);
728 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
733 pos
+= sizeof(*option
) + optlen
;
736 assert_se(pos
== len
);
737 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
742 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
744 sd_event
*e
= userdata
;
745 sd_dhcp6_lease
*lease
;
746 struct in6_addr
*addrs
;
747 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
750 log_debug("/* %s */", __func__
);
753 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
755 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
757 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
758 assert_se(!strcmp("lab.intra", domains
[0]));
759 assert_se(domains
[1] == NULL
);
761 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
762 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
764 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
765 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
767 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
768 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
769 assert_se(sd_dhcp6_client_stop(client
) >= 0);
770 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
772 assert_se(sd_dhcp6_client_set_callback(client
,
773 test_client_solicit_cb
, e
) >= 0);
775 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
777 assert_se(sd_dhcp6_client_start(client
) >= 0);
781 static int test_client_verify_information_request(DHCP6Message
*information_request
,
784 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
786 bool found_clientid
= false, found_elapsed_time
= false;
787 struct in6_addr addr
;
788 uint32_t lt_pref
, lt_valid
;
790 log_debug("/* %s */", __func__
);
792 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
793 assert_se(dhcp6_lease_new(&lease
) >= 0);
795 len
-= sizeof(DHCP6Message
);
798 DHCP6Option
*option
= (DHCP6Option
*)&information_request
->options
[pos
];
799 uint16_t optcode
= be16toh(option
->code
);
800 uint16_t optlen
= be16toh(option
->len
);
801 uint8_t *optval
= option
->data
;
804 case SD_DHCP6_OPTION_CLIENTID
:
805 assert_se(!found_clientid
);
806 found_clientid
= true;
808 assert_se(optlen
== sizeof(test_duid
));
809 memcpy(&test_duid
, optval
, sizeof(test_duid
));
813 case SD_DHCP6_OPTION_IA_NA
:
814 assert_not_reached("IA TA option must not be present");
818 case SD_DHCP6_OPTION_SERVERID
:
819 assert_not_reached("Server ID option must not be present");
823 case SD_DHCP6_OPTION_ELAPSED_TIME
:
824 assert_se(!found_elapsed_time
);
825 found_elapsed_time
= true;
827 assert_se(optlen
== 2);
832 pos
+= sizeof(*option
) + optlen
;
835 assert_se(pos
== len
);
836 assert_se(found_clientid
&& found_elapsed_time
);
838 sd_dhcp6_lease_reset_address_iter(lease
);
840 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
841 <_valid
) == -ENOMSG
);
846 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
847 const void *packet
, size_t len
) {
848 struct in6_addr mcast
=
849 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
850 DHCP6Message
*message
;
852 assert_se(s
== test_dhcp_fd
[0]);
853 assert_se(server_address
);
855 assert_se(len
> sizeof(DHCP6Message
) + 4);
856 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
858 message
= (DHCP6Message
*)packet
;
860 assert_se(message
->transaction_id
& 0x00ffffff);
862 if (test_client_message_num
== 0) {
863 test_client_verify_information_request(message
, len
);
864 test_client_send_reply(message
);
865 test_client_message_num
++;
866 } else if (test_client_message_num
== 1) {
867 test_client_verify_solicit(message
, len
);
868 test_client_send_advertise(message
);
869 test_client_message_num
++;
870 } else if (test_client_message_num
== 2) {
871 test_client_verify_request(message
, len
);
872 test_client_send_reply(message
);
873 test_client_message_num
++;
879 int dhcp6_network_bind_udp_socket(int index
, struct in6_addr
*local_address
) {
880 assert_se(index
== test_index
);
882 if (socketpair(AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_dhcp_fd
) < 0)
885 return test_dhcp_fd
[0];
888 static int test_client_solicit(sd_event
*e
) {
889 sd_dhcp6_client
*client
;
890 usec_t time_now
= now(clock_boottime_or_monotonic());
891 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
894 log_debug("/* %s */", __func__
);
896 assert_se(sd_dhcp6_client_new(&client
) >= 0);
899 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
901 assert_se(sd_dhcp6_client_set_ifindex(client
, test_index
) == 0);
902 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
905 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
907 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
909 assert_se(sd_dhcp6_client_set_information_request(client
, 42) >= 0);
910 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
913 assert_se(sd_dhcp6_client_set_callback(client
,
914 test_client_information_cb
, e
) >= 0);
916 assert_se(sd_event_add_time(e
, &hangcheck
, clock_boottime_or_monotonic(),
917 time_now
+ 2 * USEC_PER_SEC
, 0,
918 test_hangcheck
, NULL
) >= 0);
920 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
922 assert_se(sd_dhcp6_client_start(client
) >= 0);
926 hangcheck
= sd_event_source_unref(hangcheck
);
928 assert_se(!sd_dhcp6_client_unref(client
));
930 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
935 int main(int argc
, char *argv
[]) {
936 _cleanup_(sd_event_unrefp
) sd_event
*e
;
938 assert_se(sd_event_new(&e
) >= 0);
940 test_setup_logging(LOG_DEBUG
);
942 test_client_basic(e
);
944 test_option_status(e
);
945 test_advertise_option(e
);
946 test_client_solicit(e
);