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(option
, &ia
, NULL
);
300 assert_se(ia
.addresses
== NULL
);
302 option
->len
= htobe16(17);
303 r
= dhcp6_option_parse_ia(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(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(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(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(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(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(!memcmp(optval
, &msg_advertise
[26], optlen
));
454 val
= htobe32(0x0ecfa37d);
455 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
458 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
461 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
463 assert_se(dhcp6_option_parse_ia(option
, &lease
->ia
, NULL
) >= 0);
467 case SD_DHCP6_OPTION_SERVERID
:
468 assert_se(optlen
== 14);
469 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
471 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
475 case SD_DHCP6_OPTION_PREFERENCE
:
476 assert_se(optlen
== 1);
479 assert_se(dhcp6_lease_set_preference(lease
,
483 case SD_DHCP6_OPTION_ELAPSED_TIME
:
484 assert_se(optlen
== 2);
488 case SD_DHCP6_OPTION_DNS_SERVERS
:
489 assert_se(optlen
== 16);
490 assert_se(dhcp6_lease_set_dns(lease
, optval
,
494 case SD_DHCP6_OPTION_DOMAIN_LIST
:
495 assert_se(optlen
== 11);
496 assert_se(dhcp6_lease_set_domains(lease
, optval
,
500 case SD_DHCP6_OPTION_SNTP_SERVERS
:
501 assert_se(optlen
== 16);
502 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
510 pos
+= sizeof(*option
) + optlen
;
513 assert_se(pos
== len
);
514 assert_se(opt_clientid
);
516 sd_dhcp6_lease_reset_address_iter(lease
);
517 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
519 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
520 assert_se(lt_pref
== 150);
521 assert_se(lt_valid
== 180);
522 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
523 <_valid
) == -ENOMSG
);
525 sd_dhcp6_lease_reset_address_iter(lease
);
526 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
528 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
529 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
530 <_valid
) == -ENOMSG
);
531 sd_dhcp6_lease_reset_address_iter(lease
);
532 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
534 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
535 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
536 <_valid
) == -ENOMSG
);
538 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
539 assert_se(len
== 14);
540 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
542 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
543 assert_se(preference
== 0);
545 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
547 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
549 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
551 assert_se(!strcmp("lab.intra", domains
[0]));
552 assert_se(domains
[1] == NULL
);
554 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
556 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
561 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
562 assert_not_reached("Test case should have completed in 2 seconds");
567 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
569 sd_event
*e
= userdata
;
570 sd_dhcp6_lease
*lease
;
571 const struct in6_addr
*addrs
;
574 log_debug("/* %s */", __func__
);
577 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
579 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
581 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
582 assert_se(!strcmp("lab.intra", domains
[0]));
583 assert_se(domains
[1] == NULL
);
585 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
586 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
588 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
589 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
591 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
596 static int test_client_send_reply(DHCP6Message
*request
) {
599 reply
.transaction_id
= request
->transaction_id
;
600 reply
.type
= DHCP6_REPLY
;
602 memcpy(msg_reply
, &reply
.transaction_id
, 4);
604 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
606 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
608 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
609 == sizeof(msg_reply
));
614 static int test_client_verify_request(DHCP6Message
*request
, size_t len
) {
615 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
616 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
617 found_elapsed_time
= false, found_fqdn
= false;
618 uint32_t lt_pref
, lt_valid
;
619 struct in6_addr addr
;
623 log_debug("/* %s */", __func__
);
625 assert_se(request
->type
== DHCP6_REQUEST
);
626 assert_se(dhcp6_lease_new(&lease
) >= 0);
628 len
-= sizeof(DHCP6Message
);
631 DHCP6Option
*option
= (DHCP6Option
*)&request
->options
[pos
];
632 uint16_t optcode
= be16toh(option
->code
);
633 uint16_t optlen
= be16toh(option
->len
);
634 uint8_t *optval
= option
->data
;
637 case SD_DHCP6_OPTION_CLIENTID
:
638 assert_se(!found_clientid
);
639 found_clientid
= true;
641 assert_se(!memcmp(optval
, &test_duid
,
646 case SD_DHCP6_OPTION_IA_NA
:
647 assert_se(!found_iana
);
650 assert_se(optlen
== 40);
651 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
653 /* T1 and T2 should not be set. */
655 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
656 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
658 /* Then, this should refuse all addresses. */
659 assert_se(dhcp6_option_parse_ia(option
, &lease
->ia
, NULL
) >= 0);
663 case SD_DHCP6_OPTION_SERVERID
:
664 assert_se(!found_serverid
);
665 found_serverid
= true;
667 assert_se(optlen
== 14);
668 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
672 case SD_DHCP6_OPTION_ELAPSED_TIME
:
673 assert_se(!found_elapsed_time
);
674 found_elapsed_time
= true;
676 assert_se(optlen
== 2);
679 case SD_DHCP6_OPTION_FQDN
:
680 assert_se(!found_fqdn
);
683 assert_se(optlen
== 17);
685 assert_se(optval
[0] == 0x01);
686 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
690 pos
+= sizeof(*option
) + optlen
;
693 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
696 sd_dhcp6_lease_reset_address_iter(lease
);
697 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
, <_valid
) == -ENOMSG
);
702 static int test_client_send_advertise(DHCP6Message
*solicit
) {
703 DHCP6Message advertise
;
705 advertise
.transaction_id
= solicit
->transaction_id
;
706 advertise
.type
= DHCP6_ADVERTISE
;
708 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
710 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
712 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
714 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
715 == sizeof(msg_advertise
));
720 static int test_client_verify_solicit(DHCP6Message
*solicit
, size_t len
) {
721 bool found_clientid
= false, found_iana
= false,
722 found_elapsed_time
= false, found_fqdn
= false;
725 log_debug("/* %s */", __func__
);
727 assert_se(solicit
->type
== DHCP6_SOLICIT
);
729 len
-= sizeof(DHCP6Message
);
732 DHCP6Option
*option
= (DHCP6Option
*)&solicit
->options
[pos
];
733 uint16_t optcode
= be16toh(option
->code
);
734 uint16_t optlen
= be16toh(option
->len
);
735 uint8_t *optval
= option
->data
;
738 case SD_DHCP6_OPTION_CLIENTID
:
739 assert_se(!found_clientid
);
740 found_clientid
= true;
742 assert_se(optlen
== sizeof(test_duid
));
743 memcpy(&test_duid
, optval
, sizeof(test_duid
));
747 case SD_DHCP6_OPTION_IA_NA
:
748 assert_se(!found_iana
);
751 assert_se(optlen
== 12);
753 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
757 case SD_DHCP6_OPTION_ELAPSED_TIME
:
758 assert_se(!found_elapsed_time
);
759 found_elapsed_time
= true;
761 assert_se(optlen
== 2);
765 case SD_DHCP6_OPTION_FQDN
:
766 assert_se(!found_fqdn
);
769 assert_se(optlen
== 17);
771 assert_se(optval
[0] == 0x01);
772 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
777 pos
+= sizeof(*option
) + optlen
;
780 assert_se(pos
== len
);
781 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
786 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
788 sd_event
*e
= userdata
;
789 sd_dhcp6_lease
*lease
;
790 const struct in6_addr
*addrs
;
791 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
795 log_debug("/* %s */", __func__
);
798 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
800 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
802 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
803 assert_se(!strcmp("lab.intra", domains
[0]));
804 assert_se(domains
[1] == NULL
);
806 assert_se(sd_dhcp6_lease_get_fqdn(lease
, &fqdn
) >= 0);
807 assert_se(streq(fqdn
, "client.intra"));
809 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
810 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
812 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
813 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
815 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
816 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
817 assert_se(sd_dhcp6_client_stop(client
) >= 0);
818 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
820 assert_se(sd_dhcp6_client_set_callback(client
,
821 test_client_solicit_cb
, e
) >= 0);
823 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
825 assert_se(sd_dhcp6_client_start(client
) >= 0);
829 static int test_client_verify_information_request(DHCP6Message
*information_request
,
832 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
834 bool found_clientid
= false, found_elapsed_time
= false;
835 struct in6_addr addr
;
836 uint32_t lt_pref
, lt_valid
;
838 log_debug("/* %s */", __func__
);
840 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
841 assert_se(dhcp6_lease_new(&lease
) >= 0);
843 len
-= sizeof(DHCP6Message
);
846 DHCP6Option
*option
= (DHCP6Option
*)&information_request
->options
[pos
];
847 uint16_t optcode
= be16toh(option
->code
);
848 uint16_t optlen
= be16toh(option
->len
);
849 uint8_t *optval
= option
->data
;
852 case SD_DHCP6_OPTION_CLIENTID
:
853 assert_se(!found_clientid
);
854 found_clientid
= true;
856 assert_se(optlen
== sizeof(test_duid
));
857 memcpy(&test_duid
, optval
, sizeof(test_duid
));
861 case SD_DHCP6_OPTION_IA_NA
:
862 assert_not_reached("IA TA option must not be present");
866 case SD_DHCP6_OPTION_SERVERID
:
867 assert_not_reached("Server ID option must not be present");
871 case SD_DHCP6_OPTION_ELAPSED_TIME
:
872 assert_se(!found_elapsed_time
);
873 found_elapsed_time
= true;
875 assert_se(optlen
== 2);
880 pos
+= sizeof(*option
) + optlen
;
883 assert_se(pos
== len
);
884 assert_se(found_clientid
&& found_elapsed_time
);
886 sd_dhcp6_lease_reset_address_iter(lease
);
888 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
889 <_valid
) == -ENOMSG
);
894 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
895 const void *packet
, size_t len
) {
896 struct in6_addr mcast
=
897 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
898 DHCP6Message
*message
;
900 assert_se(s
== test_dhcp_fd
[0]);
901 assert_se(server_address
);
903 assert_se(len
> sizeof(DHCP6Message
) + 4);
904 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
906 message
= (DHCP6Message
*)packet
;
908 assert_se(message
->transaction_id
& 0x00ffffff);
910 if (test_client_message_num
== 0) {
911 test_client_verify_information_request(message
, len
);
912 test_client_send_reply(message
);
913 test_client_message_num
++;
914 } else if (test_client_message_num
== 1) {
915 test_client_verify_solicit(message
, len
);
916 test_client_send_advertise(message
);
917 test_client_message_num
++;
918 } else if (test_client_message_num
== 2) {
919 test_client_verify_request(message
, len
);
920 test_client_send_reply(message
);
921 test_client_message_num
++;
927 int dhcp6_network_bind_udp_socket(int ifindex
, struct in6_addr
*local_address
) {
928 assert_se(ifindex
== test_ifindex
);
930 if (socketpair(AF_UNIX
, SOCK_STREAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_dhcp_fd
) < 0)
933 return test_dhcp_fd
[0];
936 static int test_client_solicit(sd_event
*e
) {
937 sd_dhcp6_client
*client
;
938 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
941 log_debug("/* %s */", __func__
);
943 assert_se(sd_dhcp6_client_new(&client
) >= 0);
946 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
948 assert_se(sd_dhcp6_client_set_ifindex(client
, test_ifindex
) == 0);
949 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
952 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
954 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
956 assert_se(sd_dhcp6_client_set_information_request(client
, 42) >= 0);
957 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
960 assert_se(sd_dhcp6_client_set_callback(client
,
961 test_client_information_cb
, e
) >= 0);
963 assert_se(sd_event_add_time_relative(e
, &hangcheck
, clock_boottime_or_monotonic(),
965 test_hangcheck
, NULL
) >= 0);
967 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
969 assert_se(sd_dhcp6_client_start(client
) >= 0);
973 hangcheck
= sd_event_source_unref(hangcheck
);
975 assert_se(!sd_dhcp6_client_unref(client
));
977 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
982 int main(int argc
, char *argv
[]) {
983 _cleanup_(sd_event_unrefp
) sd_event
*e
;
985 assert_se(sd_event_new(&e
) >= 0);
987 test_setup_logging(LOG_DEBUG
);
989 test_client_basic(e
);
991 test_option_status(e
);
992 test_advertise_option(e
);
993 test_client_solicit(e
);
994 test_parse_domain(e
);