1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <net/ethernet.h>
7 #include <net/if_arp.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 "memory-util.h"
22 #include "socket-util.h"
24 #include "time-util.h"
27 static struct ether_addr mac_addr
= {
28 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
31 static sd_event_source
*hangcheck
;
32 static int test_dhcp_fd
[2];
33 static int test_index
= 42;
34 static int test_client_message_num
;
35 static be32_t test_iaid
= 0;
36 static uint8_t test_duid
[14] = { };
38 static int test_client_basic(sd_event
*e
) {
39 sd_dhcp6_client
*client
;
42 log_debug("/* %s */", __func__
);
44 assert_se(sd_dhcp6_client_new(&client
) >= 0);
47 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
49 assert_se(sd_dhcp6_client_set_ifindex(client
, 15) == 0);
50 assert_se(sd_dhcp6_client_set_ifindex(client
, -42) == -EINVAL
);
51 assert_se(sd_dhcp6_client_set_ifindex(client
, -1) == 0);
52 assert_se(sd_dhcp6_client_set_ifindex(client
, 42) >= 0);
54 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
58 assert_se(sd_dhcp6_client_set_fqdn(client
, "host") == 1);
59 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.domain") == 1);
60 assert_se(sd_dhcp6_client_set_fqdn(client
, NULL
) == 1);
61 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host") == -EINVAL
);
62 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host.domain") == -EINVAL
);
64 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CLIENTID
) == 0);
65 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EEXIST
);
66 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
) == -EEXIST
);
67 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVERS
) == -EEXIST
);
68 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN_LIST
) == -EEXIST
);
69 assert_se(sd_dhcp6_client_set_request_option(client
, 10) == 0);
71 assert_se(sd_dhcp6_client_set_information_request(client
, 1) >= 0);
73 assert_se(sd_dhcp6_client_get_information_request(client
, &v
) >= 0);
75 assert_se(sd_dhcp6_client_set_information_request(client
, 0) >= 0);
77 assert_se(sd_dhcp6_client_get_information_request(client
, &v
) >= 0);
81 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
84 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
85 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
88 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
89 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
92 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
93 assert_se(sd_dhcp6_client_set_prefix_delegation(client
, 1) >= 0);
95 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
98 assert_se(sd_dhcp6_client_get_prefix_delegation(client
, &v
) >= 0);
101 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, NULL
) >= 0);
103 assert_se(sd_dhcp6_client_detach_event(client
) >= 0);
104 assert_se(!sd_dhcp6_client_unref(client
));
109 static int test_option(sd_event
*e
) {
112 0x00, SD_DHCP6_OPTION_ORO
, 0x00, 0x07,
113 'A', 'B', 'C', 'D', 'E', 'F', 'G',
114 0x00, SD_DHCP6_OPTION_VENDOR_CLASS
, 0x00, 0x09,
115 '1', '2', '3', '4', '5', '6', '7', '8', '9',
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 uint8_t *optval
, *buf
, *out
;
128 size_t zero
= 0, pos
= 3;
129 size_t buflen
= sizeof(packet
), outlen
= sizeof(result
);
131 log_debug("/* %s */", __func__
);
133 assert_se(buflen
== outlen
);
135 assert_se(dhcp6_option_parse(&buf
, &zero
, &optcode
, &optlen
,
136 &optval
) == -ENOMSG
);
143 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
146 assert_se(buf
== &packet
[pos
]);
147 assert_se(optcode
== SD_DHCP6_OPTION_ORO
);
148 assert_se(optlen
== 7);
149 assert_se(buflen
+ pos
== sizeof(packet
));
151 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
153 assert_se(out
== &result
[pos
]);
154 assert_se(*out
== 0x00);
156 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
159 assert_se(buf
== &packet
[pos
]);
160 assert_se(optcode
== SD_DHCP6_OPTION_VENDOR_CLASS
);
161 assert_se(optlen
== 9);
162 assert_se(buflen
+ pos
== sizeof(packet
));
164 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
166 assert_se(out
== &result
[pos
]);
167 assert_se(*out
== 'B');
169 assert_se(memcmp(packet
, result
, sizeof(packet
)) == 0);
174 static int test_option_status(sd_event
*e
) {
175 uint8_t option1
[] = {
177 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
178 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
180 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
182 static const uint8_t option2
[] = {
184 0x00, 0x03, 0x00, 0x2e, 0x1a, 0x1d, 0x1a, 0x1d,
185 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
187 0x00, 0x05, 0x00, 0x1e,
188 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
189 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
190 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
192 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
194 static const uint8_t option3
[] = {
196 0x00, 0x03, 0x00, 0x34, 0x1a, 0x1d, 0x1a, 0x1d,
197 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
199 0x00, 0x05, 0x00, 0x24,
200 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
201 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
202 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
204 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
207 static const uint8_t option4
[] = {
209 0x00, 0x19, 0x00, 0x2f, 0x1a, 0x1d, 0x1a, 0x1d,
210 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
212 0x00, 0x1a, 0x00, 0x1f,
213 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
214 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
215 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
220 static const uint8_t option5
[] = {
222 0x00, 0x19, 0x00, 0x52, 0x1a, 0x1d, 0x1a, 0x1d,
223 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
224 /* IA PD Prefix #1 */
225 0x00, 0x1a, 0x00, 0x1f,
226 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
227 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
228 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
232 /* IA PD Prefix #2 */
233 0x00, 0x1a, 0x00, 0x1f,
234 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
235 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l
, 0xd0,
236 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
244 log_debug("/* %s */", __func__
);
247 option
= (DHCP6Option
*)option1
;
248 assert_se(sizeof(option1
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
250 r
= dhcp6_option_parse_ia(option
, &ia
);
251 assert_se(r
== -EINVAL
);
252 assert_se(ia
.addresses
== NULL
);
254 option
->len
= htobe16(17);
255 r
= dhcp6_option_parse_ia(option
, &ia
);
256 assert_se(r
== -ENOBUFS
);
257 assert_se(ia
.addresses
== NULL
);
259 option
->len
= htobe16(sizeof(DHCP6Option
));
260 r
= dhcp6_option_parse_ia(option
, &ia
);
261 assert_se(r
== -ENOBUFS
);
262 assert_se(ia
.addresses
== NULL
);
265 option
= (DHCP6Option
*)option2
;
266 assert_se(sizeof(option2
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
268 r
= dhcp6_option_parse_ia(option
, &ia
);
270 assert_se(ia
.addresses
== NULL
);
273 option
= (DHCP6Option
*)option3
;
274 assert_se(sizeof(option3
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
276 r
= dhcp6_option_parse_ia(option
, &ia
);
278 assert_se(ia
.addresses
!= NULL
);
279 dhcp6_lease_free_ia(&ia
);
282 option
= (DHCP6Option
*)option4
;
283 assert_se(sizeof(option4
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
285 r
= dhcp6_option_parse_ia(option
, &pd
);
287 assert_se(pd
.addresses
!= NULL
);
288 assert_se(memcmp(&pd
.ia_pd
.id
, &option4
[4], 4) == 0);
289 assert_se(memcmp(&pd
.ia_pd
.lifetime_t1
, &option4
[8], 4) == 0);
290 assert_se(memcmp(&pd
.ia_pd
.lifetime_t2
, &option4
[12], 4) == 0);
291 dhcp6_lease_free_ia(&pd
);
294 option
= (DHCP6Option
*)option5
;
295 assert_se(sizeof(option5
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
297 r
= dhcp6_option_parse_ia(option
, &pd
);
299 assert_se(pd
.addresses
!= NULL
);
300 dhcp6_lease_free_ia(&pd
);
305 static uint8_t msg_advertise
[198] = {
306 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
307 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
308 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
309 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
310 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
311 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
312 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
313 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
314 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
315 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
316 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
317 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
318 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
319 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
320 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
321 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
322 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
324 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
325 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
326 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
328 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
329 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
330 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
333 static uint8_t msg_reply
[173] = {
334 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
335 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
336 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
337 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
338 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
339 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
340 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
341 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
342 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
343 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
344 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
345 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
346 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
347 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
348 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
349 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
350 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
352 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
353 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
354 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x01
358 static uint8_t fqdn_wire
[16] = {
359 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
360 0x05, 'i', 'n', 't', 'r', 'a', 0x00
363 static int test_advertise_option(sd_event
*e
) {
364 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
365 DHCP6Message
*advertise
= (DHCP6Message
*)msg_advertise
;
366 size_t len
= sizeof(msg_advertise
) - sizeof(DHCP6Message
), pos
= 0;
368 uint8_t preference
= 255;
369 struct in6_addr addr
;
370 uint32_t lt_pref
, lt_valid
;
373 bool opt_clientid
= false;
374 struct in6_addr
*addrs
;
377 log_debug("/* %s */", __func__
);
379 assert_se(len
>= sizeof(DHCP6Message
));
381 assert_se(dhcp6_lease_new(&lease
) >= 0);
383 assert_se(advertise
->type
== DHCP6_ADVERTISE
);
384 assert_se((be32toh(advertise
->transaction_id
) & 0x00ffffff) ==
388 DHCP6Option
*option
= (DHCP6Option
*)&advertise
->options
[pos
];
389 const uint16_t optcode
= be16toh(option
->code
);
390 const uint16_t optlen
= be16toh(option
->len
);
391 uint8_t *optval
= option
->data
;
394 case SD_DHCP6_OPTION_CLIENTID
:
395 assert_se(optlen
== 14);
400 case SD_DHCP6_OPTION_IA_NA
:
401 assert_se(optlen
== 94);
402 assert_se(!memcmp(optval
, &msg_advertise
[26], optlen
));
404 val
= htobe32(0x0ecfa37d);
405 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
408 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
411 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
413 assert_se(dhcp6_option_parse_ia(option
, &lease
->ia
) >= 0);
417 case SD_DHCP6_OPTION_SERVERID
:
418 assert_se(optlen
== 14);
419 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
421 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
425 case SD_DHCP6_OPTION_PREFERENCE
:
426 assert_se(optlen
== 1);
429 assert_se(dhcp6_lease_set_preference(lease
,
433 case SD_DHCP6_OPTION_ELAPSED_TIME
:
434 assert_se(optlen
== 2);
438 case SD_DHCP6_OPTION_DNS_SERVERS
:
439 assert_se(optlen
== 16);
440 assert_se(dhcp6_lease_set_dns(lease
, optval
,
444 case SD_DHCP6_OPTION_DOMAIN_LIST
:
445 assert_se(optlen
== 11);
446 assert_se(dhcp6_lease_set_domains(lease
, optval
,
450 case SD_DHCP6_OPTION_SNTP_SERVERS
:
451 assert_se(optlen
== 16);
452 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
460 pos
+= sizeof(*option
) + optlen
;
463 assert_se(pos
== len
);
464 assert_se(opt_clientid
);
466 sd_dhcp6_lease_reset_address_iter(lease
);
467 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
469 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
470 assert_se(lt_pref
== 150);
471 assert_se(lt_valid
== 180);
472 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
473 <_valid
) == -ENOMSG
);
475 sd_dhcp6_lease_reset_address_iter(lease
);
476 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
478 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
479 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
480 <_valid
) == -ENOMSG
);
481 sd_dhcp6_lease_reset_address_iter(lease
);
482 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
484 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
485 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
486 <_valid
) == -ENOMSG
);
488 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
489 assert_se(len
== 14);
490 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
492 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
493 assert_se(preference
== 0);
495 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
497 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
499 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
501 assert_se(!strcmp("lab.intra", domains
[0]));
502 assert_se(domains
[1] == NULL
);
504 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
506 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
511 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
512 assert_not_reached("Test case should have completed in 2 seconds");
517 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
519 sd_event
*e
= userdata
;
520 sd_dhcp6_lease
*lease
;
521 struct in6_addr
*addrs
;
524 log_debug("/* %s */", __func__
);
527 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
529 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
531 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
532 assert_se(!strcmp("lab.intra", domains
[0]));
533 assert_se(domains
[1] == NULL
);
535 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
536 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
538 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
539 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
541 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
546 static int test_client_send_reply(DHCP6Message
*request
) {
549 reply
.transaction_id
= request
->transaction_id
;
550 reply
.type
= DHCP6_REPLY
;
552 memcpy(msg_reply
, &reply
.transaction_id
, 4);
554 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
556 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
558 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
559 == sizeof(msg_reply
));
564 static int test_client_verify_request(DHCP6Message
*request
, size_t len
) {
565 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
567 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
568 found_elapsed_time
= false, found_fqdn
= false;
569 struct in6_addr addr
;
571 uint32_t lt_pref
, lt_valid
;
573 log_debug("/* %s */", __func__
);
575 assert_se(request
->type
== DHCP6_REQUEST
);
576 assert_se(dhcp6_lease_new(&lease
) >= 0);
578 len
-= sizeof(DHCP6Message
);
581 DHCP6Option
*option
= (DHCP6Option
*)&request
->options
[pos
];
582 uint16_t optcode
= be16toh(option
->code
);
583 uint16_t optlen
= be16toh(option
->len
);
584 uint8_t *optval
= option
->data
;
587 case SD_DHCP6_OPTION_CLIENTID
:
588 assert_se(!found_clientid
);
589 found_clientid
= true;
591 assert_se(!memcmp(optval
, &test_duid
,
596 case SD_DHCP6_OPTION_IA_NA
:
597 assert_se(!found_iana
);
600 assert_se(optlen
== 40);
601 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
604 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
607 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
609 assert_se(!dhcp6_option_parse_ia(option
, &lease
->ia
));
613 case SD_DHCP6_OPTION_SERVERID
:
614 assert_se(!found_serverid
);
615 found_serverid
= true;
617 assert_se(optlen
== 14);
618 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
622 case SD_DHCP6_OPTION_ELAPSED_TIME
:
623 assert_se(!found_elapsed_time
);
624 found_elapsed_time
= true;
626 assert_se(optlen
== 2);
629 case SD_DHCP6_OPTION_FQDN
:
630 assert_se(!found_fqdn
);
633 assert_se(optlen
== 17);
635 assert_se(optval
[0] == 0x01);
636 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
640 pos
+= sizeof(*option
) + optlen
;
643 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
646 sd_dhcp6_lease_reset_address_iter(lease
);
647 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
649 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
650 assert_se(lt_pref
== 150);
651 assert_se(lt_valid
== 180);
653 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
654 <_valid
) == -ENOMSG
);
659 static int test_client_send_advertise(DHCP6Message
*solicit
) {
660 DHCP6Message advertise
;
662 advertise
.transaction_id
= solicit
->transaction_id
;
663 advertise
.type
= DHCP6_ADVERTISE
;
665 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
667 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
669 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
671 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
672 == sizeof(msg_advertise
));
677 static int test_client_verify_solicit(DHCP6Message
*solicit
, size_t len
) {
678 bool found_clientid
= false, found_iana
= false,
679 found_elapsed_time
= false, found_fqdn
= false;
682 log_debug("/* %s */", __func__
);
684 assert_se(solicit
->type
== DHCP6_SOLICIT
);
686 len
-= sizeof(DHCP6Message
);
689 DHCP6Option
*option
= (DHCP6Option
*)&solicit
->options
[pos
];
690 uint16_t optcode
= be16toh(option
->code
);
691 uint16_t optlen
= be16toh(option
->len
);
692 uint8_t *optval
= option
->data
;
695 case SD_DHCP6_OPTION_CLIENTID
:
696 assert_se(!found_clientid
);
697 found_clientid
= true;
699 assert_se(optlen
== sizeof(test_duid
));
700 memcpy(&test_duid
, optval
, sizeof(test_duid
));
704 case SD_DHCP6_OPTION_IA_NA
:
705 assert_se(!found_iana
);
708 assert_se(optlen
== 12);
710 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
714 case SD_DHCP6_OPTION_ELAPSED_TIME
:
715 assert_se(!found_elapsed_time
);
716 found_elapsed_time
= true;
718 assert_se(optlen
== 2);
722 case SD_DHCP6_OPTION_FQDN
:
723 assert_se(!found_fqdn
);
726 assert_se(optlen
== 17);
728 assert_se(optval
[0] == 0x01);
729 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
734 pos
+= sizeof(*option
) + optlen
;
737 assert_se(pos
== len
);
738 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
743 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
745 sd_event
*e
= userdata
;
746 sd_dhcp6_lease
*lease
;
747 struct in6_addr
*addrs
;
748 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
751 log_debug("/* %s */", __func__
);
754 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
756 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
758 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
759 assert_se(!strcmp("lab.intra", domains
[0]));
760 assert_se(domains
[1] == NULL
);
762 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
763 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
765 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
766 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
768 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
769 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
770 assert_se(sd_dhcp6_client_stop(client
) >= 0);
771 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
773 assert_se(sd_dhcp6_client_set_callback(client
,
774 test_client_solicit_cb
, e
) >= 0);
776 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
778 assert_se(sd_dhcp6_client_start(client
) >= 0);
782 static int test_client_verify_information_request(DHCP6Message
*information_request
,
785 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
787 bool found_clientid
= false, found_elapsed_time
= false;
788 struct in6_addr addr
;
789 uint32_t lt_pref
, lt_valid
;
791 log_debug("/* %s */", __func__
);
793 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
794 assert_se(dhcp6_lease_new(&lease
) >= 0);
796 len
-= sizeof(DHCP6Message
);
799 DHCP6Option
*option
= (DHCP6Option
*)&information_request
->options
[pos
];
800 uint16_t optcode
= be16toh(option
->code
);
801 uint16_t optlen
= be16toh(option
->len
);
802 uint8_t *optval
= option
->data
;
805 case SD_DHCP6_OPTION_CLIENTID
:
806 assert_se(!found_clientid
);
807 found_clientid
= true;
809 assert_se(optlen
== sizeof(test_duid
));
810 memcpy(&test_duid
, optval
, sizeof(test_duid
));
814 case SD_DHCP6_OPTION_IA_NA
:
815 assert_not_reached("IA TA option must not be present");
819 case SD_DHCP6_OPTION_SERVERID
:
820 assert_not_reached("Server ID option must not be present");
824 case SD_DHCP6_OPTION_ELAPSED_TIME
:
825 assert_se(!found_elapsed_time
);
826 found_elapsed_time
= true;
828 assert_se(optlen
== 2);
833 pos
+= sizeof(*option
) + optlen
;
836 assert_se(pos
== len
);
837 assert_se(found_clientid
&& found_elapsed_time
);
839 sd_dhcp6_lease_reset_address_iter(lease
);
841 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
842 <_valid
) == -ENOMSG
);
847 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
848 const void *packet
, size_t len
) {
849 struct in6_addr mcast
=
850 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
851 DHCP6Message
*message
;
853 assert_se(s
== test_dhcp_fd
[0]);
854 assert_se(server_address
);
856 assert_se(len
> sizeof(DHCP6Message
) + 4);
857 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
859 message
= (DHCP6Message
*)packet
;
861 assert_se(message
->transaction_id
& 0x00ffffff);
863 if (test_client_message_num
== 0) {
864 test_client_verify_information_request(message
, len
);
865 test_client_send_reply(message
);
866 test_client_message_num
++;
867 } else if (test_client_message_num
== 1) {
868 test_client_verify_solicit(message
, len
);
869 test_client_send_advertise(message
);
870 test_client_message_num
++;
871 } else if (test_client_message_num
== 2) {
872 test_client_verify_request(message
, len
);
873 test_client_send_reply(message
);
874 test_client_message_num
++;
880 int dhcp6_network_bind_udp_socket(int index
, struct in6_addr
*local_address
) {
881 assert_se(index
== test_index
);
883 if (socketpair(AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_dhcp_fd
) < 0)
886 return test_dhcp_fd
[0];
889 static int test_client_solicit(sd_event
*e
) {
890 sd_dhcp6_client
*client
;
891 usec_t time_now
= now(clock_boottime_or_monotonic());
892 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
895 log_debug("/* %s */", __func__
);
897 assert_se(sd_dhcp6_client_new(&client
) >= 0);
900 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
902 assert_se(sd_dhcp6_client_set_ifindex(client
, test_index
) == 0);
903 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
906 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
908 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
910 assert_se(sd_dhcp6_client_set_information_request(client
, 42) >= 0);
911 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
914 assert_se(sd_dhcp6_client_set_callback(client
,
915 test_client_information_cb
, e
) >= 0);
917 assert_se(sd_event_add_time(e
, &hangcheck
, clock_boottime_or_monotonic(),
918 time_now
+ 2 * USEC_PER_SEC
, 0,
919 test_hangcheck
, NULL
) >= 0);
921 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
923 assert_se(sd_dhcp6_client_start(client
) >= 0);
927 hangcheck
= sd_event_source_unref(hangcheck
);
929 assert_se(!sd_dhcp6_client_unref(client
));
931 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
936 int main(int argc
, char *argv
[]) {
937 _cleanup_(sd_event_unrefp
) sd_event
*e
;
939 assert_se(sd_event_new(&e
) >= 0);
941 test_setup_logging(LOG_DEBUG
);
943 test_client_basic(e
);
945 test_option_status(e
);
946 test_advertise_option(e
);
947 test_client_solicit(e
);