1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
8 #include <net/ethernet.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
15 #include "sd-dhcp6-client.h"
18 #include "dhcp6-internal.h"
19 #include "dhcp6-lease-internal.h"
20 #include "dhcp6-protocol.h"
23 #include "socket-util.h"
26 static struct ether_addr mac_addr
= {
27 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
30 static bool verbose
= true;
32 static sd_event_source
*hangcheck
;
33 static int test_dhcp_fd
[2];
34 static int test_index
= 42;
35 static int test_client_message_num
;
36 static be32_t test_iaid
= 0;
37 static uint8_t test_duid
[14] = { };
39 static int test_client_basic(sd_event
*e
) {
40 sd_dhcp6_client
*client
;
43 printf("* %s\n", __FUNCTION__
);
45 assert_se(sd_dhcp6_client_new(&client
) >= 0);
48 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
50 assert_se(sd_dhcp6_client_set_ifindex(client
, 15) == 0);
51 assert_se(sd_dhcp6_client_set_ifindex(client
, -42) == -EINVAL
);
52 assert_se(sd_dhcp6_client_set_ifindex(client
, -1) == 0);
53 assert_se(sd_dhcp6_client_set_ifindex(client
, 42) >= 0);
55 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
59 assert_se(sd_dhcp6_client_set_fqdn(client
, "host") == 1);
60 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.domain") == 1);
61 assert_se(sd_dhcp6_client_set_fqdn(client
, NULL
) == 1);
62 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host") == -EINVAL
);
63 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host.domain") == -EINVAL
);
65 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CLIENTID
) == -EINVAL
);
66 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EEXIST
);
67 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
) == -EEXIST
);
68 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVERS
) == -EEXIST
);
69 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN_LIST
) == -EEXIST
);
70 assert_se(sd_dhcp6_client_set_request_option(client
, 10) == -EINVAL
);
72 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, NULL
) >= 0);
74 assert_se(sd_dhcp6_client_detach_event(client
) >= 0);
75 assert_se(!sd_dhcp6_client_unref(client
));
80 static int test_option(sd_event
*e
) {
83 0x00, SD_DHCP6_OPTION_ORO
, 0x00, 0x07,
84 'A', 'B', 'C', 'D', 'E', 'F', 'G',
85 0x00, SD_DHCP6_OPTION_VENDOR_CLASS
, 0x00, 0x09,
86 '1', '2', '3', '4', '5', '6', '7', '8', '9',
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 uint8_t *optval
, *buf
, *out
;
99 size_t zero
= 0, pos
= 3;
100 size_t buflen
= sizeof(packet
), outlen
= sizeof(result
);
103 printf("* %s\n", __FUNCTION__
);
105 assert_se(buflen
== outlen
);
107 assert_se(dhcp6_option_parse(&buf
, &zero
, &optcode
, &optlen
,
108 &optval
) == -ENOMSG
);
115 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
118 assert_se(buf
== &packet
[pos
]);
119 assert_se(optcode
== SD_DHCP6_OPTION_ORO
);
120 assert_se(optlen
== 7);
121 assert_se(buflen
+ pos
== sizeof(packet
));
123 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
125 assert_se(out
== &result
[pos
]);
126 assert_se(*out
== 0x00);
128 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
131 assert_se(buf
== &packet
[pos
]);
132 assert_se(optcode
== SD_DHCP6_OPTION_VENDOR_CLASS
);
133 assert_se(optlen
== 9);
134 assert_se(buflen
+ pos
== sizeof(packet
));
136 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
138 assert_se(out
== &result
[pos
]);
139 assert_se(*out
== 'B');
141 assert_se(memcmp(packet
, result
, sizeof(packet
)) == 0);
146 static int test_option_status(sd_event
*e
) {
147 uint8_t option1
[] = {
149 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
150 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
152 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
154 static const uint8_t option2
[] = {
156 0x00, 0x03, 0x00, 0x2e, 0x1a, 0x1d, 0x1a, 0x1d,
157 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
159 0x00, 0x05, 0x00, 0x1e,
160 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
161 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
162 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
164 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
166 static const uint8_t option3
[] = {
168 0x00, 0x03, 0x00, 0x34, 0x1a, 0x1d, 0x1a, 0x1d,
169 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
171 0x00, 0x05, 0x00, 0x24,
172 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
173 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
174 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
176 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
179 static const uint8_t option4
[] = {
181 0x00, 0x19, 0x00, 0x2f, 0x1a, 0x1d, 0x1a, 0x1d,
182 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
184 0x00, 0x1a, 0x00, 0x1f,
185 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
186 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
187 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
192 static const uint8_t option5
[] = {
194 0x00, 0x19, 0x00, 0x52, 0x1a, 0x1d, 0x1a, 0x1d,
195 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
196 /* IA PD Prefix #1 */
197 0x00, 0x1a, 0x00, 0x1f,
198 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
199 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
200 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
204 /* IA PD Prefix #2 */
205 0x00, 0x1a, 0x00, 0x1f,
206 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
207 0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l
, 0xd0,
208 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
217 printf("* %s\n", __FUNCTION__
);
220 option
= (DHCP6Option
*)option1
;
221 assert_se(sizeof(option1
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
223 r
= dhcp6_option_parse_ia(option
, &ia
);
224 assert_se(r
== -EINVAL
);
225 assert_se(ia
.addresses
== NULL
);
227 option
->len
= htobe16(17);
228 r
= dhcp6_option_parse_ia(option
, &ia
);
229 assert_se(r
== -ENOBUFS
);
230 assert_se(ia
.addresses
== NULL
);
232 option
->len
= htobe16(sizeof(DHCP6Option
));
233 r
= dhcp6_option_parse_ia(option
, &ia
);
234 assert_se(r
== -ENOBUFS
);
235 assert_se(ia
.addresses
== NULL
);
238 option
= (DHCP6Option
*)option2
;
239 assert_se(sizeof(option2
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
241 r
= dhcp6_option_parse_ia(option
, &ia
);
243 assert_se(ia
.addresses
== NULL
);
246 option
= (DHCP6Option
*)option3
;
247 assert_se(sizeof(option3
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
249 r
= dhcp6_option_parse_ia(option
, &ia
);
251 assert_se(ia
.addresses
!= NULL
);
252 dhcp6_lease_free_ia(&ia
);
255 option
= (DHCP6Option
*)option4
;
256 assert_se(sizeof(option4
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
258 r
= dhcp6_option_parse_ia(option
, &pd
);
260 assert_se(pd
.addresses
!= NULL
);
261 assert_se(memcmp(&pd
.ia_pd
.id
, &option4
[4], 4) == 0);
262 assert_se(memcmp(&pd
.ia_pd
.lifetime_t1
, &option4
[8], 4) == 0);
263 assert_se(memcmp(&pd
.ia_pd
.lifetime_t2
, &option4
[12], 4) == 0);
264 dhcp6_lease_free_ia(&pd
);
267 option
= (DHCP6Option
*)option5
;
268 assert_se(sizeof(option5
) == sizeof(DHCP6Option
) + be16toh(option
->len
));
270 r
= dhcp6_option_parse_ia(option
, &pd
);
272 assert_se(pd
.addresses
!= NULL
);
273 dhcp6_lease_free_ia(&pd
);
278 static uint8_t msg_advertise
[198] = {
279 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
280 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
281 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
282 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
283 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
284 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
285 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
286 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
287 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
288 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
289 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
290 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
291 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
292 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
293 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
294 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
295 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
297 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
298 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
299 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
301 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
302 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
303 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
306 static uint8_t msg_reply
[173] = {
307 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
308 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
309 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
310 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
311 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
312 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
313 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
314 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
315 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
316 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
317 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
318 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
319 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
320 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
321 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
322 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
323 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
325 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
326 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
327 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x01
331 static uint8_t fqdn_wire
[16] = {
332 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
333 0x05, 'i', 'n', 't', 'r', 'a', 0x00
336 static int test_advertise_option(sd_event
*e
) {
337 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
338 DHCP6Message
*advertise
= (DHCP6Message
*)msg_advertise
;
339 size_t len
= sizeof(msg_advertise
) - sizeof(DHCP6Message
), pos
= 0;
341 uint8_t preference
= 255;
342 struct in6_addr addr
;
343 uint32_t lt_pref
, lt_valid
;
346 bool opt_clientid
= false;
347 struct in6_addr
*addrs
;
351 printf("* %s\n", __FUNCTION__
);
353 assert_se(len
>= sizeof(DHCP6Message
));
355 assert_se(dhcp6_lease_new(&lease
) >= 0);
357 assert_se(advertise
->type
== DHCP6_ADVERTISE
);
358 assert_se((be32toh(advertise
->transaction_id
) & 0x00ffffff) ==
362 DHCP6Option
*option
= (DHCP6Option
*)&advertise
->options
[pos
];
363 const uint16_t optcode
= be16toh(option
->code
);
364 const uint16_t optlen
= be16toh(option
->len
);
365 uint8_t *optval
= option
->data
;
368 case SD_DHCP6_OPTION_CLIENTID
:
369 assert_se(optlen
== 14);
374 case SD_DHCP6_OPTION_IA_NA
:
375 assert_se(optlen
== 94);
376 assert_se(!memcmp(optval
, &msg_advertise
[26], optlen
));
378 val
= htobe32(0x0ecfa37d);
379 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
382 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
385 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
387 assert_se(dhcp6_option_parse_ia(option
, &lease
->ia
) >= 0);
391 case SD_DHCP6_OPTION_SERVERID
:
392 assert_se(optlen
== 14);
393 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
395 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
399 case SD_DHCP6_OPTION_PREFERENCE
:
400 assert_se(optlen
== 1);
403 assert_se(dhcp6_lease_set_preference(lease
,
407 case SD_DHCP6_OPTION_ELAPSED_TIME
:
408 assert_se(optlen
== 2);
412 case SD_DHCP6_OPTION_DNS_SERVERS
:
413 assert_se(optlen
== 16);
414 assert_se(dhcp6_lease_set_dns(lease
, optval
,
418 case SD_DHCP6_OPTION_DOMAIN_LIST
:
419 assert_se(optlen
== 11);
420 assert_se(dhcp6_lease_set_domains(lease
, optval
,
424 case SD_DHCP6_OPTION_SNTP_SERVERS
:
425 assert_se(optlen
== 16);
426 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
434 pos
+= sizeof(*option
) + optlen
;
437 assert_se(pos
== len
);
438 assert_se(opt_clientid
);
440 sd_dhcp6_lease_reset_address_iter(lease
);
441 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
443 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
444 assert_se(lt_pref
== 150);
445 assert_se(lt_valid
== 180);
446 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
447 <_valid
) == -ENOMSG
);
449 sd_dhcp6_lease_reset_address_iter(lease
);
450 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
452 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
453 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
454 <_valid
) == -ENOMSG
);
455 sd_dhcp6_lease_reset_address_iter(lease
);
456 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
458 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
459 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
460 <_valid
) == -ENOMSG
);
462 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
463 assert_se(len
== 14);
464 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
466 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
467 assert_se(preference
== 0);
469 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
471 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
473 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
475 assert_se(!strcmp("lab.intra", domains
[0]));
476 assert_se(domains
[1] == NULL
);
478 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
480 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
485 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
486 assert_not_reached("Test case should have completed in 2 seconds");
491 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
493 sd_event
*e
= userdata
;
494 sd_dhcp6_lease
*lease
;
495 struct in6_addr
*addrs
;
499 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
501 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
503 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
504 assert_se(!strcmp("lab.intra", domains
[0]));
505 assert_se(domains
[1] == NULL
);
507 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
508 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
510 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
511 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
513 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
516 printf(" got DHCPv6 event %d\n", event
);
521 static int test_client_send_reply(DHCP6Message
*request
) {
524 reply
.transaction_id
= request
->transaction_id
;
525 reply
.type
= DHCP6_REPLY
;
527 memcpy(msg_reply
, &reply
.transaction_id
, 4);
529 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
531 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
533 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
534 == sizeof(msg_reply
));
539 static int test_client_verify_request(DHCP6Message
*request
, size_t len
) {
540 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
542 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
543 found_elapsed_time
= false, found_fqdn
= false;
544 struct in6_addr addr
;
546 uint32_t lt_pref
, lt_valid
;
548 assert_se(request
->type
== DHCP6_REQUEST
);
550 assert_se(dhcp6_lease_new(&lease
) >= 0);
552 len
-= sizeof(DHCP6Message
);
555 DHCP6Option
*option
= (DHCP6Option
*)&request
->options
[pos
];
556 uint16_t optcode
= be16toh(option
->code
);
557 uint16_t optlen
= be16toh(option
->len
);
558 uint8_t *optval
= option
->data
;
561 case SD_DHCP6_OPTION_CLIENTID
:
562 assert_se(!found_clientid
);
563 found_clientid
= true;
565 assert_se(!memcmp(optval
, &test_duid
,
570 case SD_DHCP6_OPTION_IA_NA
:
571 assert_se(!found_iana
);
574 assert_se(optlen
== 40);
575 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
578 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
581 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
583 assert_se(!dhcp6_option_parse_ia(option
, &lease
->ia
));
587 case SD_DHCP6_OPTION_SERVERID
:
588 assert_se(!found_serverid
);
589 found_serverid
= true;
591 assert_se(optlen
== 14);
592 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
596 case SD_DHCP6_OPTION_ELAPSED_TIME
:
597 assert_se(!found_elapsed_time
);
598 found_elapsed_time
= true;
600 assert_se(optlen
== 2);
603 case SD_DHCP6_OPTION_FQDN
:
604 assert_se(!found_fqdn
);
607 assert_se(optlen
== 17);
609 assert_se(optval
[0] == 0x01);
610 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
614 pos
+= sizeof(*option
) + optlen
;
617 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
620 sd_dhcp6_lease_reset_address_iter(lease
);
621 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
623 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
624 assert_se(lt_pref
== 150);
625 assert_se(lt_valid
== 180);
627 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
628 <_valid
) == -ENOMSG
);
633 static int test_client_send_advertise(DHCP6Message
*solicit
) {
634 DHCP6Message advertise
;
636 advertise
.transaction_id
= solicit
->transaction_id
;
637 advertise
.type
= DHCP6_ADVERTISE
;
639 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
641 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
643 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
645 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
646 == sizeof(msg_advertise
));
651 static int test_client_verify_solicit(DHCP6Message
*solicit
, size_t len
) {
652 bool found_clientid
= false, found_iana
= false,
653 found_elapsed_time
= false, found_fqdn
= false;
656 assert_se(solicit
->type
== DHCP6_SOLICIT
);
658 len
-= sizeof(DHCP6Message
);
661 DHCP6Option
*option
= (DHCP6Option
*)&solicit
->options
[pos
];
662 uint16_t optcode
= be16toh(option
->code
);
663 uint16_t optlen
= be16toh(option
->len
);
664 uint8_t *optval
= option
->data
;
667 case SD_DHCP6_OPTION_CLIENTID
:
668 assert_se(!found_clientid
);
669 found_clientid
= true;
671 assert_se(optlen
== sizeof(test_duid
));
672 memcpy(&test_duid
, optval
, sizeof(test_duid
));
676 case SD_DHCP6_OPTION_IA_NA
:
677 assert_se(!found_iana
);
680 assert_se(optlen
== 12);
682 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
686 case SD_DHCP6_OPTION_ELAPSED_TIME
:
687 assert_se(!found_elapsed_time
);
688 found_elapsed_time
= true;
690 assert_se(optlen
== 2);
694 case SD_DHCP6_OPTION_FQDN
:
695 assert_se(!found_fqdn
);
698 assert_se(optlen
== 17);
700 assert_se(optval
[0] == 0x01);
701 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
706 pos
+= sizeof(*option
) + optlen
;
709 assert_se(pos
== len
);
710 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
715 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
717 sd_event
*e
= userdata
;
718 sd_dhcp6_lease
*lease
;
719 struct in6_addr
*addrs
;
720 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
724 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
726 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
728 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
729 assert_se(!strcmp("lab.intra", domains
[0]));
730 assert_se(domains
[1] == NULL
);
732 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
733 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
735 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
736 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
739 printf(" got DHCPv6 event %d\n", event
);
741 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
742 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
743 assert_se(sd_dhcp6_client_stop(client
) >= 0);
744 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
746 assert_se(sd_dhcp6_client_set_callback(client
,
747 test_client_solicit_cb
, e
) >= 0);
749 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
751 assert_se(sd_dhcp6_client_start(client
) >= 0);
755 static int test_client_verify_information_request(DHCP6Message
*information_request
,
758 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
760 bool found_clientid
= false, found_elapsed_time
= false;
761 struct in6_addr addr
;
762 uint32_t lt_pref
, lt_valid
;
764 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
766 assert_se(dhcp6_lease_new(&lease
) >= 0);
768 len
-= sizeof(DHCP6Message
);
771 DHCP6Option
*option
= (DHCP6Option
*)&information_request
->options
[pos
];
772 uint16_t optcode
= be16toh(option
->code
);
773 uint16_t optlen
= be16toh(option
->len
);
774 uint8_t *optval
= option
->data
;
777 case SD_DHCP6_OPTION_CLIENTID
:
778 assert_se(!found_clientid
);
779 found_clientid
= true;
781 assert_se(optlen
== sizeof(test_duid
));
782 memcpy(&test_duid
, optval
, sizeof(test_duid
));
786 case SD_DHCP6_OPTION_IA_NA
:
787 assert_not_reached("IA TA option must not be present");
791 case SD_DHCP6_OPTION_SERVERID
:
792 assert_not_reached("Server ID option must not be present");
796 case SD_DHCP6_OPTION_ELAPSED_TIME
:
797 assert_se(!found_elapsed_time
);
798 found_elapsed_time
= true;
800 assert_se(optlen
== 2);
805 pos
+= sizeof(*option
) + optlen
;
808 assert_se(pos
== len
);
809 assert_se(found_clientid
&& found_elapsed_time
);
811 sd_dhcp6_lease_reset_address_iter(lease
);
813 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
814 <_valid
) == -ENOMSG
);
819 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
820 const void *packet
, size_t len
) {
821 struct in6_addr mcast
=
822 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
823 DHCP6Message
*message
;
825 assert_se(s
== test_dhcp_fd
[0]);
826 assert_se(server_address
);
828 assert_se(len
> sizeof(DHCP6Message
) + 4);
830 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
832 message
= (DHCP6Message
*)packet
;
834 assert_se(message
->transaction_id
& 0x00ffffff);
836 if (test_client_message_num
== 0) {
837 test_client_verify_information_request(message
, len
);
838 test_client_send_reply(message
);
839 test_client_message_num
++;
840 } else if (test_client_message_num
== 1) {
841 test_client_verify_solicit(message
, len
);
842 test_client_send_advertise(message
);
843 test_client_message_num
++;
844 } else if (test_client_message_num
== 2) {
845 test_client_verify_request(message
, len
);
846 test_client_send_reply(message
);
847 test_client_message_num
++;
853 int dhcp6_network_bind_udp_socket(int index
, struct in6_addr
*local_address
) {
854 assert_se(index
== test_index
);
856 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, test_dhcp_fd
) < 0)
859 return test_dhcp_fd
[0];
862 static int test_client_solicit(sd_event
*e
) {
863 sd_dhcp6_client
*client
;
864 usec_t time_now
= now(clock_boottime_or_monotonic());
865 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
869 printf("* %s\n", __FUNCTION__
);
871 assert_se(sd_dhcp6_client_new(&client
) >= 0);
874 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
876 assert_se(sd_dhcp6_client_set_ifindex(client
, test_index
) == 0);
877 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
880 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
882 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
883 assert_se(val
== false);
884 assert_se(sd_dhcp6_client_set_information_request(client
, true) >= 0);
885 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
886 assert_se(val
== true);
888 assert_se(sd_dhcp6_client_set_callback(client
,
889 test_client_information_cb
, e
) >= 0);
891 assert_se(sd_event_add_time(e
, &hangcheck
, clock_boottime_or_monotonic(),
892 time_now
+ 2 * USEC_PER_SEC
, 0,
893 test_hangcheck
, NULL
) >= 0);
895 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
897 assert_se(sd_dhcp6_client_start(client
) >= 0);
901 hangcheck
= sd_event_source_unref(hangcheck
);
903 assert_se(!sd_dhcp6_client_unref(client
));
905 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
910 int main(int argc
, char *argv
[]) {
911 _cleanup_(sd_event_unrefp
) sd_event
*e
;
913 assert_se(sd_event_new(&e
) >= 0);
915 log_set_max_level(LOG_DEBUG
);
916 log_parse_environment();
919 test_client_basic(e
);
921 test_option_status(e
);
922 test_advertise_option(e
);
923 test_client_solicit(e
);