1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
23 #include "string-util.h"
26 #include "time-util.h"
29 static struct ether_addr mac_addr
= {
30 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
33 static sd_event_source
*hangcheck
;
34 static int test_dhcp_fd
[2];
35 static int test_ifindex
= 42;
36 static int test_client_message_num
;
37 static be32_t test_iaid
= 0;
38 static uint8_t test_duid
[14] = { };
40 static int test_client_basic(sd_event
*e
) {
41 sd_dhcp6_client
*client
;
44 log_debug("/* %s */", __func__
);
46 assert_se(sd_dhcp6_client_new(&client
) >= 0);
49 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
51 assert_se(sd_dhcp6_client_set_ifindex(client
, 15) == 0);
52 assert_se(sd_dhcp6_client_set_ifindex(client
, -42) == -EINVAL
);
53 assert_se(sd_dhcp6_client_set_ifindex(client
, -1) == -EINVAL
);
54 assert_se(sd_dhcp6_client_set_ifindex(client
, 42) >= 0);
56 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
60 assert_se(sd_dhcp6_client_set_fqdn(client
, "host") == 1);
61 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.domain") == 1);
62 assert_se(sd_dhcp6_client_set_fqdn(client
, NULL
) == 1);
63 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host") == -EINVAL
);
64 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host.domain") == -EINVAL
);
66 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CLIENTID
) == 0);
67 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EEXIST
);
68 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
) == -EEXIST
);
69 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVERS
) == -EEXIST
);
70 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN_LIST
) == -EEXIST
);
71 assert_se(sd_dhcp6_client_set_request_option(client
, 10) == 0);
73 assert_se(sd_dhcp6_client_set_information_request(client
, 1) >= 0);
75 assert_se(sd_dhcp6_client_get_information_request(client
, &v
) >= 0);
77 assert_se(sd_dhcp6_client_set_information_request(client
, 0) >= 0);
79 assert_se(sd_dhcp6_client_get_information_request(client
, &v
) >= 0);
83 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
86 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
87 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
90 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
91 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
94 assert_se(sd_dhcp6_client_set_address_request(client
, 1) >= 0);
95 assert_se(sd_dhcp6_client_set_prefix_delegation(client
, 1) >= 0);
97 assert_se(sd_dhcp6_client_get_address_request(client
, &v
) >= 0);
100 assert_se(sd_dhcp6_client_get_prefix_delegation(client
, &v
) >= 0);
103 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, NULL
) >= 0);
105 assert_se(sd_dhcp6_client_detach_event(client
) >= 0);
106 assert_se(!sd_dhcp6_client_unref(client
));
111 static int test_parse_domain(sd_event
*e
) {
117 log_debug("/* %s */", __func__
);
119 data
= (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0 };
120 r
= dhcp6_option_parse_domainname(data
, 13, &domain
);
123 assert_se(streq(domain
, "example.com"));
126 data
= (uint8_t []) { 4, 't', 'e', 's', 't' };
127 r
= dhcp6_option_parse_domainname(data
, 5, &domain
);
130 assert_se(streq(domain
, "test"));
133 data
= (uint8_t []) { 0 };
134 r
= dhcp6_option_parse_domainname(data
, 1, &domain
);
137 data
= (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
138 6, 'f', 'o', 'o', 'b', 'a', 'r', 0 };
139 r
= dhcp6_option_parse_domainname_list(data
, 21, &list
);
142 assert_se(streq(list
[0], "example.com"));
143 assert_se(streq(list
[1], "foobar"));
146 data
= (uint8_t []) { 1, 'a', 0, 20, 'b', 'c' };
147 r
= dhcp6_option_parse_domainname_list(data
, 6, &list
);
150 data
= (uint8_t []) { 0 , 0 };
151 r
= dhcp6_option_parse_domainname_list(data
, 2, &list
);
157 static int test_option(sd_event
*e
) {
160 0x00, SD_DHCP6_OPTION_ORO
, 0x00, 0x07,
161 'A', 'B', 'C', 'D', 'E', 'F', 'G',
162 0x00, SD_DHCP6_OPTION_VENDOR_CLASS
, 0x00, 0x09,
163 '1', '2', '3', '4', '5', '6', '7', '8', '9',
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 uint8_t *optval
, *buf
, *out
;
176 size_t zero
= 0, pos
= 3;
177 size_t buflen
= sizeof(packet
), outlen
= sizeof(result
);
179 log_debug("/* %s */", __func__
);
181 assert_se(buflen
== outlen
);
183 assert_se(dhcp6_option_parse(&buf
, &zero
, &optcode
, &optlen
,
184 &optval
) == -ENOMSG
);
191 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
194 assert_se(buf
== &packet
[pos
]);
195 assert_se(optcode
== SD_DHCP6_OPTION_ORO
);
196 assert_se(optlen
== 7);
197 assert_se(buflen
+ pos
== sizeof(packet
));
199 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
201 assert_se(out
== &result
[pos
]);
202 assert_se(*out
== 0x00);
204 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
207 assert_se(buf
== &packet
[pos
]);
208 assert_se(optcode
== SD_DHCP6_OPTION_VENDOR_CLASS
);
209 assert_se(optlen
== 9);
210 assert_se(buflen
+ pos
== sizeof(packet
));
212 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
214 assert_se(out
== &result
[pos
]);
215 assert_se(*out
== 'B');
217 assert_se(memcmp(packet
, result
, sizeof(packet
)) == 0);
222 static int test_option_status(sd_event
*e
) {
223 uint8_t option1
[] = {
225 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
226 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
228 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
230 static const uint8_t option2
[] = {
232 0x00, 0x03, 0x00, 0x2e, 0x1a, 0x1d, 0x1a, 0x1d,
233 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
235 0x00, 0x05, 0x00, 0x1e,
236 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
237 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
238 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
240 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
242 static const uint8_t option3
[] = {
244 0x00, 0x03, 0x00, 0x34, 0x1a, 0x1d, 0x1a, 0x1d,
245 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
247 0x00, 0x05, 0x00, 0x24,
248 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
249 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
250 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
252 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
255 static const uint8_t option4
[] = {
257 0x00, 0x19, 0x00, 0x2f, 0x1a, 0x1d, 0x1a, 0x1d,
258 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
260 0x00, 0x1a, 0x00, 0x1f,
261 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
262 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
263 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
268 static const uint8_t option5
[] = {
270 0x00, 0x19, 0x00, 0x52, 0x1a, 0x1d, 0x1a, 0x1d,
271 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
272 /* IA PD Prefix #1 */
273 0x00, 0x1a, 0x00, 0x1f,
274 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
275 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
276 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
280 /* IA PD Prefix #2 */
281 0x00, 0x1a, 0x00, 0x1f,
282 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
283 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l
, 0xd0,
284 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
292 log_debug("/* %s */", __func__
);
295 option
= (DHCP6Option
*)option1
;
296 assert_se(sizeof(option1
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
298 r
= dhcp6_option_parse_ia(NULL
, option
, &ia
, NULL
);
300 assert_se(ia
.addresses
== NULL
);
302 option
->len
= htobe16(17);
303 r
= dhcp6_option_parse_ia(NULL
, option
, &ia
, NULL
);
304 assert_se(r
== -ENOBUFS
);
305 assert_se(ia
.addresses
== NULL
);
307 option
->len
= htobe16(sizeof(DHCP6Option
));
308 r
= dhcp6_option_parse_ia(NULL
, option
, &ia
, NULL
);
309 assert_se(r
== -ENOBUFS
);
310 assert_se(ia
.addresses
== NULL
);
313 option
= (DHCP6Option
*)option2
;
314 assert_se(sizeof(option2
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
316 r
= dhcp6_option_parse_ia(NULL
, option
, &ia
, NULL
);
318 assert_se(ia
.addresses
== NULL
);
321 option
= (DHCP6Option
*)option3
;
322 assert_se(sizeof(option3
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
324 r
= dhcp6_option_parse_ia(NULL
, option
, &ia
, NULL
);
326 assert_se(ia
.addresses
!= NULL
);
327 dhcp6_lease_free_ia(&ia
);
330 option
= (DHCP6Option
*)option4
;
331 assert_se(sizeof(option4
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
333 r
= dhcp6_option_parse_ia(NULL
, option
, &pd
, NULL
);
335 assert_se(pd
.addresses
!= NULL
);
336 assert_se(memcmp(&pd
.ia_pd
.id
, &option4
[4], 4) == 0);
337 assert_se(memcmp(&pd
.ia_pd
.lifetime_t1
, &option4
[8], 4) == 0);
338 assert_se(memcmp(&pd
.ia_pd
.lifetime_t2
, &option4
[12], 4) == 0);
339 dhcp6_lease_free_ia(&pd
);
342 option
= (DHCP6Option
*)option5
;
343 assert_se(sizeof(option5
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
345 r
= dhcp6_option_parse_ia(NULL
, option
, &pd
, NULL
);
347 assert_se(pd
.addresses
!= NULL
);
348 dhcp6_lease_free_ia(&pd
);
353 static uint8_t msg_advertise
[198] = {
354 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
355 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
356 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
357 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
358 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
359 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
360 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
361 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
362 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
363 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
364 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
365 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
366 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
367 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
368 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
369 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
370 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
372 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
373 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
374 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
376 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
377 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
378 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
381 static uint8_t msg_reply
[191] = {
382 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
383 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
384 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
385 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
386 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
387 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
388 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
389 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
390 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
391 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
392 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
393 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
394 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
395 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
396 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
397 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
398 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
400 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
401 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
402 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
403 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x00,
404 0x0e, 0x01, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e,
405 0x74, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61
408 static uint8_t fqdn_wire
[16] = {
409 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
410 0x05, 'i', 'n', 't', 'r', 'a', 0x00
413 static int test_advertise_option(sd_event
*e
) {
414 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
415 DHCP6Message
*advertise
= (DHCP6Message
*)msg_advertise
;
416 size_t len
= sizeof(msg_advertise
) - sizeof(DHCP6Message
), pos
= 0;
417 uint32_t lt_pref
, lt_valid
;
418 bool opt_clientid
= false;
419 const struct in6_addr
*addrs
;
420 uint8_t preference
= 255;
421 struct in6_addr addr
;
427 log_debug("/* %s */", __func__
);
429 assert_se(len
>= sizeof(DHCP6Message
));
431 assert_se(dhcp6_lease_new(&lease
) >= 0);
433 assert_se(advertise
->type
== DHCP6_ADVERTISE
);
434 assert_se((be32toh(advertise
->transaction_id
) & 0x00ffffff) ==
438 DHCP6Option
*option
= (DHCP6Option
*)&advertise
->options
[pos
];
439 const uint16_t optcode
= be16toh(option
->code
);
440 const uint16_t optlen
= be16toh(option
->len
);
441 uint8_t *optval
= option
->data
;
444 case SD_DHCP6_OPTION_CLIENTID
:
445 assert_se(optlen
== 14);
450 case SD_DHCP6_OPTION_IA_NA
:
451 assert_se(optlen
== 94);
452 assert_se(optval
== &msg_advertise
[26]);
453 assert_se(!memcmp(optval
, &msg_advertise
[26], optlen
));
455 val
= htobe32(0x0ecfa37d);
456 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
459 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
462 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
464 assert_se(dhcp6_option_parse_ia(NULL
, option
, &lease
->ia
, NULL
) >= 0);
468 case SD_DHCP6_OPTION_SERVERID
:
469 assert_se(optlen
== 14);
470 assert_se(optval
== &msg_advertise
[179]);
471 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
473 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
477 case SD_DHCP6_OPTION_PREFERENCE
:
478 assert_se(optlen
== 1);
481 assert_se(dhcp6_lease_set_preference(lease
,
485 case SD_DHCP6_OPTION_ELAPSED_TIME
:
486 assert_se(optlen
== 2);
490 case SD_DHCP6_OPTION_DNS_SERVERS
:
491 assert_se(optlen
== 16);
492 assert_se(dhcp6_lease_set_dns(lease
, optval
,
496 case SD_DHCP6_OPTION_DOMAIN_LIST
:
497 assert_se(optlen
== 11);
498 assert_se(dhcp6_lease_set_domains(lease
, optval
,
502 case SD_DHCP6_OPTION_SNTP_SERVERS
:
503 assert_se(optlen
== 16);
504 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
512 pos
+= sizeof(*option
) + optlen
;
515 assert_se(pos
== len
);
516 assert_se(opt_clientid
);
518 sd_dhcp6_lease_reset_address_iter(lease
);
519 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
521 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
522 assert_se(lt_pref
== 150);
523 assert_se(lt_valid
== 180);
524 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
525 <_valid
) == -ENOMSG
);
527 sd_dhcp6_lease_reset_address_iter(lease
);
528 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
530 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
531 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
532 <_valid
) == -ENOMSG
);
533 sd_dhcp6_lease_reset_address_iter(lease
);
534 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
536 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
537 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
538 <_valid
) == -ENOMSG
);
540 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
541 assert_se(len
== 14);
542 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
544 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
545 assert_se(preference
== 0);
547 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
549 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
551 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
553 assert_se(!strcmp("lab.intra", domains
[0]));
554 assert_se(domains
[1] == NULL
);
556 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
558 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
563 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
564 assert_not_reached("Test case should have completed in 2 seconds");
569 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
571 sd_event
*e
= userdata
;
572 sd_dhcp6_lease
*lease
;
573 const struct in6_addr
*addrs
;
576 log_debug("/* %s */", __func__
);
579 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
581 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
583 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
584 assert_se(!strcmp("lab.intra", domains
[0]));
585 assert_se(domains
[1] == NULL
);
587 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
588 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
590 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
591 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
593 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
598 static int test_client_send_reply(DHCP6Message
*request
) {
601 reply
.transaction_id
= request
->transaction_id
;
602 reply
.type
= DHCP6_REPLY
;
604 memcpy(msg_reply
, &reply
.transaction_id
, 4);
606 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
608 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
610 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
611 == sizeof(msg_reply
));
616 static int test_client_verify_request(DHCP6Message
*request
, size_t len
) {
617 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
618 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
619 found_elapsed_time
= false, found_fqdn
= false;
620 uint32_t lt_pref
, lt_valid
;
621 struct in6_addr addr
;
625 log_debug("/* %s */", __func__
);
627 assert_se(request
->type
== DHCP6_REQUEST
);
628 assert_se(dhcp6_lease_new(&lease
) >= 0);
630 len
-= sizeof(DHCP6Message
);
633 DHCP6Option
*option
= (DHCP6Option
*)&request
->options
[pos
];
634 uint16_t optcode
= be16toh(option
->code
);
635 uint16_t optlen
= be16toh(option
->len
);
636 uint8_t *optval
= option
->data
;
639 case SD_DHCP6_OPTION_CLIENTID
:
640 assert_se(!found_clientid
);
641 found_clientid
= true;
643 assert_se(!memcmp(optval
, &test_duid
,
648 case SD_DHCP6_OPTION_IA_NA
:
649 assert_se(!found_iana
);
652 assert_se(optlen
== 40);
653 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
655 /* T1 and T2 should not be set. */
657 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
658 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
660 /* Then, this should refuse all addresses. */
661 assert_se(dhcp6_option_parse_ia(NULL
, option
, &lease
->ia
, NULL
) >= 0);
665 case SD_DHCP6_OPTION_SERVERID
:
666 assert_se(!found_serverid
);
667 found_serverid
= true;
669 assert_se(optlen
== 14);
670 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
674 case SD_DHCP6_OPTION_ELAPSED_TIME
:
675 assert_se(!found_elapsed_time
);
676 found_elapsed_time
= true;
678 assert_se(optlen
== 2);
681 case SD_DHCP6_OPTION_FQDN
:
682 assert_se(!found_fqdn
);
685 assert_se(optlen
== 17);
687 assert_se(optval
[0] == 0x01);
688 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
692 pos
+= sizeof(*option
) + optlen
;
695 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
698 sd_dhcp6_lease_reset_address_iter(lease
);
699 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
, <_valid
) == -ENOMSG
);
704 static int test_client_send_advertise(DHCP6Message
*solicit
) {
705 DHCP6Message advertise
;
707 advertise
.transaction_id
= solicit
->transaction_id
;
708 advertise
.type
= DHCP6_ADVERTISE
;
710 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
712 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
714 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
716 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
717 == sizeof(msg_advertise
));
722 static int test_client_verify_solicit(DHCP6Message
*solicit
, size_t len
) {
723 bool found_clientid
= false, found_iana
= false,
724 found_elapsed_time
= false, found_fqdn
= false;
727 log_debug("/* %s */", __func__
);
729 assert_se(solicit
->type
== DHCP6_SOLICIT
);
731 len
-= sizeof(DHCP6Message
);
734 DHCP6Option
*option
= (DHCP6Option
*)&solicit
->options
[pos
];
735 uint16_t optcode
= be16toh(option
->code
);
736 uint16_t optlen
= be16toh(option
->len
);
737 uint8_t *optval
= option
->data
;
740 case SD_DHCP6_OPTION_CLIENTID
:
741 assert_se(!found_clientid
);
742 found_clientid
= true;
744 assert_se(optlen
== sizeof(test_duid
));
745 memcpy(&test_duid
, optval
, sizeof(test_duid
));
749 case SD_DHCP6_OPTION_IA_NA
:
750 assert_se(!found_iana
);
753 assert_se(optlen
== 12);
755 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
759 case SD_DHCP6_OPTION_ELAPSED_TIME
:
760 assert_se(!found_elapsed_time
);
761 found_elapsed_time
= true;
763 assert_se(optlen
== 2);
767 case SD_DHCP6_OPTION_FQDN
:
768 assert_se(!found_fqdn
);
771 assert_se(optlen
== 17);
773 assert_se(optval
[0] == 0x01);
774 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
779 pos
+= sizeof(*option
) + optlen
;
782 assert_se(pos
== len
);
783 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
788 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
790 sd_event
*e
= userdata
;
791 sd_dhcp6_lease
*lease
;
792 const struct in6_addr
*addrs
;
793 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
797 log_debug("/* %s */", __func__
);
800 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
802 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
804 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
805 assert_se(!strcmp("lab.intra", domains
[0]));
806 assert_se(domains
[1] == NULL
);
808 assert_se(sd_dhcp6_lease_get_fqdn(lease
, &fqdn
) >= 0);
809 assert_se(streq(fqdn
, "client.intra"));
811 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
812 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
814 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
815 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
817 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
818 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
819 assert_se(sd_dhcp6_client_stop(client
) >= 0);
820 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
822 assert_se(sd_dhcp6_client_set_callback(client
,
823 test_client_solicit_cb
, e
) >= 0);
825 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
827 assert_se(sd_dhcp6_client_start(client
) >= 0);
831 static int test_client_verify_information_request(DHCP6Message
*information_request
,
834 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
836 bool found_clientid
= false, found_elapsed_time
= false;
837 struct in6_addr addr
;
838 uint32_t lt_pref
, lt_valid
;
840 log_debug("/* %s */", __func__
);
842 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
843 assert_se(dhcp6_lease_new(&lease
) >= 0);
845 len
-= sizeof(DHCP6Message
);
848 DHCP6Option
*option
= (DHCP6Option
*)&information_request
->options
[pos
];
849 uint16_t optcode
= be16toh(option
->code
);
850 uint16_t optlen
= be16toh(option
->len
);
851 uint8_t *optval
= option
->data
;
854 case SD_DHCP6_OPTION_CLIENTID
:
855 assert_se(!found_clientid
);
856 found_clientid
= true;
858 assert_se(optlen
== sizeof(test_duid
));
859 memcpy(&test_duid
, optval
, sizeof(test_duid
));
863 case SD_DHCP6_OPTION_IA_NA
:
864 assert_not_reached("IA TA option must not be present");
868 case SD_DHCP6_OPTION_SERVERID
:
869 assert_not_reached("Server ID option must not be present");
873 case SD_DHCP6_OPTION_ELAPSED_TIME
:
874 assert_se(!found_elapsed_time
);
875 found_elapsed_time
= true;
877 assert_se(optlen
== 2);
882 pos
+= sizeof(*option
) + optlen
;
885 assert_se(pos
== len
);
886 assert_se(found_clientid
&& found_elapsed_time
);
888 sd_dhcp6_lease_reset_address_iter(lease
);
890 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
891 <_valid
) == -ENOMSG
);
896 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
897 const void *packet
, size_t len
) {
898 struct in6_addr mcast
=
899 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
900 DHCP6Message
*message
;
902 assert_se(s
== test_dhcp_fd
[0]);
903 assert_se(server_address
);
905 assert_se(len
> sizeof(DHCP6Message
) + 4);
906 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
908 message
= (DHCP6Message
*)packet
;
910 assert_se(message
->transaction_id
& 0x00ffffff);
912 if (test_client_message_num
== 0) {
913 test_client_verify_information_request(message
, len
);
914 test_client_send_reply(message
);
915 test_client_message_num
++;
916 } else if (test_client_message_num
== 1) {
917 test_client_verify_solicit(message
, len
);
918 test_client_send_advertise(message
);
919 test_client_message_num
++;
920 } else if (test_client_message_num
== 2) {
921 test_client_verify_request(message
, len
);
922 test_client_send_reply(message
);
923 test_client_message_num
++;
929 int dhcp6_network_bind_udp_socket(int ifindex
, struct in6_addr
*local_address
) {
930 assert_se(ifindex
== test_ifindex
);
932 if (socketpair(AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_dhcp_fd
) < 0)
935 return test_dhcp_fd
[0];
938 static int test_client_solicit(sd_event
*e
) {
939 sd_dhcp6_client
*client
;
940 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
943 log_debug("/* %s */", __func__
);
945 assert_se(sd_dhcp6_client_new(&client
) >= 0);
948 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
950 assert_se(sd_dhcp6_client_set_ifindex(client
, test_ifindex
) == 0);
951 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
954 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
956 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
958 assert_se(sd_dhcp6_client_set_information_request(client
, 42) >= 0);
959 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
962 assert_se(sd_dhcp6_client_set_callback(client
,
963 test_client_information_cb
, e
) >= 0);
965 assert_se(sd_event_add_time_relative(e
, &hangcheck
, clock_boottime_or_monotonic(),
967 test_hangcheck
, NULL
) >= 0);
969 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
971 assert_se(sd_dhcp6_client_start(client
) >= 0);
975 hangcheck
= sd_event_source_unref(hangcheck
);
977 assert_se(!sd_dhcp6_client_unref(client
));
979 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
984 int main(int argc
, char *argv
[]) {
985 _cleanup_(sd_event_unrefp
) sd_event
*e
;
987 assert_se(sd_event_new(&e
) >= 0);
989 test_setup_logging(LOG_DEBUG
);
991 test_client_basic(e
);
993 test_option_status(e
);
994 test_advertise_option(e
);
995 test_client_solicit(e
);
996 test_parse_domain(e
);