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