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