]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp6-client.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp6-client.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <net/ethernet.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include "sd-dhcp6-client.h"
29 #include "sd-event.h"
30
31 #include "dhcp6-internal.h"
32 #include "dhcp6-lease-internal.h"
33 #include "dhcp6-protocol.h"
34 #include "fd-util.h"
35 #include "macro.h"
36 #include "socket-util.h"
37 #include "virt.h"
38
39 static struct ether_addr mac_addr = {
40 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
41 };
42
43 static bool verbose = true;
44
45 static sd_event_source *hangcheck;
46 static int test_dhcp_fd[2];
47 static int test_index = 42;
48 static int test_client_message_num;
49 static be32_t test_iaid = 0;
50 static uint8_t test_duid[14] = { };
51
52 static int test_client_basic(sd_event *e) {
53 sd_dhcp6_client *client;
54
55 if (verbose)
56 printf("* %s\n", __FUNCTION__);
57
58 assert_se(sd_dhcp6_client_new(&client) >= 0);
59 assert_se(client);
60
61 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
62
63 assert_se(sd_dhcp6_client_set_ifindex(client, 15) == 0);
64 assert_se(sd_dhcp6_client_set_ifindex(client, -42) == -EINVAL);
65 assert_se(sd_dhcp6_client_set_ifindex(client, -1) == 0);
66 assert_se(sd_dhcp6_client_set_ifindex(client, 42) >= 0);
67
68 assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
69 sizeof (mac_addr),
70 ARPHRD_ETHER) >= 0);
71
72 assert_se(sd_dhcp6_client_set_fqdn(client, "host") == 1);
73 assert_se(sd_dhcp6_client_set_fqdn(client, "host.domain") == 1);
74 assert_se(sd_dhcp6_client_set_fqdn(client, NULL) == 1);
75 assert_se(sd_dhcp6_client_set_fqdn(client, "~host") == -EINVAL);
76 assert_se(sd_dhcp6_client_set_fqdn(client, "~host.domain") == -EINVAL);
77
78 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == -EINVAL);
79 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
80 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) == -EEXIST);
81 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVERS) == -EEXIST);
82 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
83 assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
84
85 assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
86
87 assert_se(sd_dhcp6_client_detach_event(client) >= 0);
88 assert_se(!sd_dhcp6_client_unref(client));
89
90 return 0;
91 }
92
93 static int test_option(sd_event *e) {
94 uint8_t packet[] = {
95 'F', 'O', 'O',
96 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07,
97 'A', 'B', 'C', 'D', 'E', 'F', 'G',
98 0x00, SD_DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
99 '1', '2', '3', '4', '5', '6', '7', '8', '9',
100 'B', 'A', 'R',
101 };
102 uint8_t result[] = {
103 'F', 'O', 'O',
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 'B', 'A', 'R',
108 };
109 uint16_t optcode;
110 size_t optlen;
111 uint8_t *optval, *buf, *out;
112 size_t zero = 0, pos = 3;
113 size_t buflen = sizeof(packet), outlen = sizeof(result);
114
115 if (verbose)
116 printf("* %s\n", __FUNCTION__);
117
118 assert_se(buflen == outlen);
119
120 assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
121 &optval) == -ENOMSG);
122
123 buflen -= 3;
124 buf = &packet[3];
125 outlen -= 3;
126 out = &result[3];
127
128 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
129 &optval) >= 0);
130 pos += 4 + optlen;
131 assert_se(buf == &packet[pos]);
132 assert_se(optcode == SD_DHCP6_OPTION_ORO);
133 assert_se(optlen == 7);
134 assert_se(buflen + pos == sizeof(packet));
135
136 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
137 optval) >= 0);
138 assert_se(out == &result[pos]);
139 assert_se(*out == 0x00);
140
141 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
142 &optval) >= 0);
143 pos += 4 + optlen;
144 assert_se(buf == &packet[pos]);
145 assert_se(optcode == SD_DHCP6_OPTION_VENDOR_CLASS);
146 assert_se(optlen == 9);
147 assert_se(buflen + pos == sizeof(packet));
148
149 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
150 optval) >= 0);
151 assert_se(out == &result[pos]);
152 assert_se(*out == 'B');
153
154 assert_se(memcmp(packet, result, sizeof(packet)) == 0);
155
156 return 0;
157 }
158
159 static uint8_t msg_advertise[198] = {
160 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
161 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
162 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
163 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
164 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
165 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
166 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
167 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
168 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
169 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
170 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
171 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
172 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
173 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
174 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
175 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
176 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
178 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
179 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
180 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
182 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
183 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
184 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
185 };
186
187 static uint8_t msg_reply[173] = {
188 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
189 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
190 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
191 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
192 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
193 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
194 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
195 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
196 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
197 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
198 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
199 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
200 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
201 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
202 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
203 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
204 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
206 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
207 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
208 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x01
210 };
211
212 static uint8_t fqdn_wire[16] = {
213 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
214 0x05, 'i', 'n', 't', 'r', 'a', 0x00
215 };
216
217 static int test_advertise_option(sd_event *e) {
218 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
219 DHCP6Message *advertise = (DHCP6Message *)msg_advertise;
220 uint8_t *optval, *opt = msg_advertise + sizeof(DHCP6Message);
221 uint16_t optcode;
222 size_t optlen, len = sizeof(msg_advertise) - sizeof(DHCP6Message);
223 be32_t val;
224 uint8_t preference = 255;
225 struct in6_addr addr;
226 uint32_t lt_pref, lt_valid;
227 int r;
228 bool opt_clientid = false;
229 struct in6_addr *addrs;
230 char **domains;
231
232 if (verbose)
233 printf("* %s\n", __FUNCTION__);
234
235 assert_se(dhcp6_lease_new(&lease) >= 0);
236
237 assert_se(advertise->type == DHCP6_ADVERTISE);
238 assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) ==
239 0x0fb4e5);
240
241 while ((r = dhcp6_option_parse(&opt, &len, &optcode, &optlen,
242 &optval)) >= 0) {
243
244 switch(optcode) {
245 case SD_DHCP6_OPTION_CLIENTID:
246 assert_se(optlen == 14);
247
248 opt_clientid = true;
249 break;
250
251 case SD_DHCP6_OPTION_IA_NA:
252 assert_se(optlen == 94);
253 assert_se(!memcmp(optval, &msg_advertise[26], optlen));
254
255 val = htobe32(0x0ecfa37d);
256 assert_se(!memcmp(optval, &val, sizeof(val)));
257
258 val = htobe32(80);
259 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
260
261 val = htobe32(120);
262 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
263
264 assert_se(dhcp6_option_parse_ia(&optval, &optlen,
265 optcode,
266 &lease->ia) >= 0);
267
268 break;
269
270 case SD_DHCP6_OPTION_SERVERID:
271 assert_se(optlen == 14);
272 assert_se(!memcmp(optval, &msg_advertise[179], optlen));
273
274 assert_se(dhcp6_lease_set_serverid(lease, optval,
275 optlen) >= 0);
276 break;
277
278 case SD_DHCP6_OPTION_PREFERENCE:
279 assert_se(optlen == 1);
280 assert_se(!*optval);
281
282 assert_se(dhcp6_lease_set_preference(lease,
283 *optval) >= 0);
284 break;
285
286 case SD_DHCP6_OPTION_ELAPSED_TIME:
287 assert_se(optlen == 2);
288
289 break;
290
291 case SD_DHCP6_OPTION_DNS_SERVERS:
292 assert_se(optlen == 16);
293 assert_se(dhcp6_lease_set_dns(lease, optval,
294 optlen) >= 0);
295 break;
296
297 case SD_DHCP6_OPTION_DOMAIN_LIST:
298 assert_se(optlen == 11);
299 assert_se(dhcp6_lease_set_domains(lease, optval,
300 optlen) >= 0);
301 break;
302
303 case SD_DHCP6_OPTION_SNTP_SERVERS:
304 assert_se(optlen == 16);
305 assert_se(dhcp6_lease_set_sntp(lease, optval,
306 optlen) >= 0);
307 break;
308
309 default:
310 break;
311 }
312 }
313
314
315 assert_se(r == -ENOMSG);
316
317 assert_se(opt_clientid);
318
319 sd_dhcp6_lease_reset_address_iter(lease);
320 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
321 &lt_valid) >= 0);
322 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
323 assert_se(lt_pref == 150);
324 assert_se(lt_valid == 180);
325 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
326 &lt_valid) == -ENOMSG);
327
328 sd_dhcp6_lease_reset_address_iter(lease);
329 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
330 &lt_valid) >= 0);
331 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
332 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
333 &lt_valid) == -ENOMSG);
334 sd_dhcp6_lease_reset_address_iter(lease);
335 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
336 &lt_valid) >= 0);
337 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
338 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
339 &lt_valid) == -ENOMSG);
340
341 assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0);
342 assert_se(len == 14);
343 assert_se(!memcmp(opt, &msg_advertise[179], len));
344
345 assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0);
346 assert_se(preference == 0);
347
348 r = sd_dhcp6_lease_get_dns(lease, &addrs);
349 assert_se(r == 1);
350 assert_se(!memcmp(addrs, &msg_advertise[124], r * 16));
351
352 r = sd_dhcp6_lease_get_domains(lease, &domains);
353 assert_se(r == 1);
354 assert_se(!strcmp("lab.intra", domains[0]));
355 assert_se(domains[1] == NULL);
356
357 r = sd_dhcp6_lease_get_ntp_addrs(lease, &addrs);
358 assert_se(r == 1);
359 assert_se(!memcmp(addrs, &msg_advertise[159], r * 16));
360
361 return 0;
362 }
363
364 static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
365 assert_not_reached("Test case should have completed in 2 seconds");
366
367 return 0;
368 }
369
370 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
371 void *userdata) {
372 sd_event *e = userdata;
373 sd_dhcp6_lease *lease;
374 struct in6_addr *addrs;
375 char **domains;
376
377 assert_se(e);
378 assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
379
380 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
381
382 assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1);
383 assert_se(!strcmp("lab.intra", domains[0]));
384 assert_se(domains[1] == NULL);
385
386 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
387 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
388
389 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
390 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
391
392 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
393
394 if (verbose)
395 printf(" got DHCPv6 event %d\n", event);
396
397 sd_event_exit(e, 0);
398 }
399
400 static int test_client_send_reply(DHCP6Message *request) {
401 DHCP6Message reply;
402
403 reply.transaction_id = request->transaction_id;
404 reply.type = DHCP6_REPLY;
405
406 memcpy(msg_reply, &reply.transaction_id, 4);
407
408 memcpy(&msg_reply[26], test_duid, sizeof(test_duid));
409
410 memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid));
411
412 assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply))
413 == sizeof(msg_reply));
414
415 return 0;
416 }
417
418 static int test_client_verify_request(DHCP6Message *request, uint8_t *option,
419 size_t len) {
420 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
421 uint8_t *optval;
422 uint16_t optcode;
423 size_t optlen;
424 bool found_clientid = false, found_iana = false, found_serverid = false,
425 found_elapsed_time = false, found_fqdn = false;
426 int r;
427 struct in6_addr addr;
428 be32_t val;
429 uint32_t lt_pref, lt_valid;
430
431 assert_se(request->type == DHCP6_REQUEST);
432
433 assert_se(dhcp6_lease_new(&lease) >= 0);
434
435 while ((r = dhcp6_option_parse(&option, &len,
436 &optcode, &optlen, &optval)) >= 0) {
437 switch(optcode) {
438 case SD_DHCP6_OPTION_CLIENTID:
439 assert_se(!found_clientid);
440 found_clientid = true;
441
442 assert_se(!memcmp(optval, &test_duid,
443 sizeof(test_duid)));
444
445 break;
446
447 case SD_DHCP6_OPTION_IA_NA:
448 assert_se(!found_iana);
449 found_iana = true;
450
451
452 assert_se(optlen == 40);
453 assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
454
455 val = htobe32(80);
456 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
457
458 val = htobe32(120);
459 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
460
461 assert_se(!dhcp6_option_parse_ia(&optval, &optlen,
462 optcode, &lease->ia));
463
464 break;
465
466 case SD_DHCP6_OPTION_SERVERID:
467 assert_se(!found_serverid);
468 found_serverid = true;
469
470 assert_se(optlen == 14);
471 assert_se(!memcmp(&msg_advertise[179], optval, optlen));
472
473 break;
474
475 case SD_DHCP6_OPTION_ELAPSED_TIME:
476 assert_se(!found_elapsed_time);
477 found_elapsed_time = true;
478
479 assert_se(optlen == 2);
480
481 break;
482 case SD_DHCP6_OPTION_FQDN:
483 assert_se(!found_fqdn);
484 found_fqdn = true;
485
486 assert_se(optlen == 17);
487
488 assert_se(optval[0] == 0x01);
489 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
490 break;
491 }
492 }
493
494 assert_se(r == -ENOMSG);
495 assert_se(found_clientid && found_iana && found_serverid &&
496 found_elapsed_time);
497
498 sd_dhcp6_lease_reset_address_iter(lease);
499 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
500 &lt_valid) >= 0);
501 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
502 assert_se(lt_pref == 150);
503 assert_se(lt_valid == 180);
504
505 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
506 &lt_valid) == -ENOMSG);
507
508 return 0;
509 }
510
511 static int test_client_send_advertise(DHCP6Message *solicit) {
512 DHCP6Message advertise;
513
514 advertise.transaction_id = solicit->transaction_id;
515 advertise.type = DHCP6_ADVERTISE;
516
517 memcpy(msg_advertise, &advertise.transaction_id, 4);
518
519 memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
520
521 memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
522
523 assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
524 == sizeof(msg_advertise));
525
526 return 0;
527 }
528
529 static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option,
530 size_t len) {
531 uint8_t *optval;
532 uint16_t optcode;
533 size_t optlen;
534 bool found_clientid = false, found_iana = false,
535 found_elapsed_time = false, found_fqdn = false;
536 int r;
537
538 assert_se(solicit->type == DHCP6_SOLICIT);
539
540 while ((r = dhcp6_option_parse(&option, &len,
541 &optcode, &optlen, &optval)) >= 0) {
542 switch(optcode) {
543 case SD_DHCP6_OPTION_CLIENTID:
544 assert_se(!found_clientid);
545 found_clientid = true;
546
547 assert_se(optlen == sizeof(test_duid));
548 memcpy(&test_duid, optval, sizeof(test_duid));
549
550 break;
551
552 case SD_DHCP6_OPTION_IA_NA:
553 assert_se(!found_iana);
554 found_iana = true;
555
556 assert_se(optlen == 12);
557
558 memcpy(&test_iaid, optval, sizeof(test_iaid));
559
560 break;
561
562 case SD_DHCP6_OPTION_ELAPSED_TIME:
563 assert_se(!found_elapsed_time);
564 found_elapsed_time = true;
565
566 assert_se(optlen == 2);
567
568 break;
569
570 case SD_DHCP6_OPTION_FQDN:
571 assert_se(!found_fqdn);
572 found_fqdn = true;
573
574 assert_se(optlen == 17);
575
576 assert_se(optval[0] == 0x01);
577 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
578
579 break;
580 }
581 }
582
583 assert_se(r == -ENOMSG);
584 assert_se(found_clientid && found_iana && found_elapsed_time);
585
586 return 0;
587 }
588
589 static void test_client_information_cb(sd_dhcp6_client *client, int event,
590 void *userdata) {
591 sd_event *e = userdata;
592 sd_dhcp6_lease *lease;
593 struct in6_addr *addrs;
594 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
595 char **domains;
596
597 assert_se(e);
598 assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
599
600 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
601
602 assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1);
603 assert_se(!strcmp("lab.intra", domains[0]));
604 assert_se(domains[1] == NULL);
605
606 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
607 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
608
609 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
610 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
611
612 if (verbose)
613 printf(" got DHCPv6 event %d\n", event);
614
615 assert_se(sd_dhcp6_client_set_information_request(client, false) == -EBUSY);
616 assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0);
617 assert_se(sd_dhcp6_client_stop(client) >= 0);
618 assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0);
619
620 assert_se(sd_dhcp6_client_set_callback(client,
621 test_client_solicit_cb, e) >= 0);
622
623 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
624
625 assert_se(sd_dhcp6_client_start(client) >= 0);
626 }
627
628 static int test_client_verify_information_request(DHCP6Message *information_request,
629 uint8_t *option, size_t len) {
630
631 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
632 uint8_t *optval;
633 uint16_t optcode;
634 size_t optlen;
635 bool found_clientid = false, found_elapsed_time = false;
636 int r;
637 struct in6_addr addr;
638 uint32_t lt_pref, lt_valid;
639
640 assert_se(information_request->type == DHCP6_INFORMATION_REQUEST);
641
642 assert_se(dhcp6_lease_new(&lease) >= 0);
643
644 while ((r = dhcp6_option_parse(&option, &len,
645 &optcode, &optlen, &optval)) >= 0) {
646 switch(optcode) {
647 case SD_DHCP6_OPTION_CLIENTID:
648 assert_se(!found_clientid);
649 found_clientid = true;
650
651 assert_se(optlen == sizeof(test_duid));
652 memcpy(&test_duid, optval, sizeof(test_duid));
653
654 break;
655
656 case SD_DHCP6_OPTION_IA_NA:
657 assert_not_reached("IA TA option must not be present");
658
659 break;
660
661 case SD_DHCP6_OPTION_SERVERID:
662 assert_not_reached("Server ID option must not be present");
663
664 break;
665
666 case SD_DHCP6_OPTION_ELAPSED_TIME:
667 assert_se(!found_elapsed_time);
668 found_elapsed_time = true;
669
670 assert_se(optlen == 2);
671
672 break;
673 }
674 }
675
676 assert_se(r == -ENOMSG);
677 assert_se(found_clientid && found_elapsed_time);
678
679 sd_dhcp6_lease_reset_address_iter(lease);
680
681 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
682 &lt_valid) == -ENOMSG);
683
684 return 0;
685 }
686
687 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
688 const void *packet, size_t len) {
689 struct in6_addr mcast =
690 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
691 DHCP6Message *message;
692 uint8_t *option;
693
694 assert_se(s == test_dhcp_fd[0]);
695 assert_se(server_address);
696 assert_se(packet);
697 assert_se(len > sizeof(DHCP6Message) + 4);
698
699 assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
700
701 message = (DHCP6Message *)packet;
702 option = (uint8_t *)(message + 1);
703 len -= sizeof(DHCP6Message);
704
705 assert_se(message->transaction_id & 0x00ffffff);
706
707 if (test_client_message_num == 0) {
708 test_client_verify_information_request(message, option, len);
709 test_client_send_reply(message);
710 test_client_message_num++;
711 } else if (test_client_message_num == 1) {
712 test_client_verify_solicit(message, option, len);
713 test_client_send_advertise(message);
714 test_client_message_num++;
715 } else if (test_client_message_num == 2) {
716 test_client_verify_request(message, option, len);
717 test_client_send_reply(message);
718 test_client_message_num++;
719 }
720
721 return len;
722 }
723
724 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
725 assert_se(index == test_index);
726
727 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
728 return -errno;
729
730 return test_dhcp_fd[0];
731 }
732
733 static int test_client_solicit(sd_event *e) {
734 sd_dhcp6_client *client;
735 usec_t time_now = now(clock_boottime_or_monotonic());
736 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
737 int val = true;
738
739 if (verbose)
740 printf("* %s\n", __FUNCTION__);
741
742 assert_se(sd_dhcp6_client_new(&client) >= 0);
743 assert_se(client);
744
745 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
746
747 assert_se(sd_dhcp6_client_set_ifindex(client, test_index) == 0);
748 assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
749 sizeof (mac_addr),
750 ARPHRD_ETHER) >= 0);
751 assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
752
753 assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
754 assert_se(val == false);
755 assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
756 assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
757 assert_se(val == true);
758
759 assert_se(sd_dhcp6_client_set_callback(client,
760 test_client_information_cb, e) >= 0);
761
762 assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
763 time_now + 2 * USEC_PER_SEC, 0,
764 test_hangcheck, NULL) >= 0);
765
766 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
767
768 assert_se(sd_dhcp6_client_start(client) >= 0);
769
770 sd_event_loop(e);
771
772 hangcheck = sd_event_source_unref(hangcheck);
773
774 assert_se(!sd_dhcp6_client_unref(client));
775
776 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
777
778 return 0;
779 }
780
781 int main(int argc, char *argv[]) {
782 _cleanup_(sd_event_unrefp) sd_event *e;
783
784 assert_se(sd_event_new(&e) >= 0);
785
786 log_set_max_level(LOG_DEBUG);
787 log_parse_environment();
788 log_open();
789
790 test_client_basic(e);
791 test_option(e);
792 test_advertise_option(e);
793 test_client_solicit(e);
794
795 return 0;
796 }