]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp6-client.c
Merge pull request #9017 from keszybz/man-coredump
[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
8 #include <net/ethernet.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include "sd-dhcp6-client.h"
16 #include "sd-event.h"
17
18 #include "dhcp6-internal.h"
19 #include "dhcp6-lease-internal.h"
20 #include "dhcp6-protocol.h"
21 #include "fd-util.h"
22 #include "macro.h"
23 #include "socket-util.h"
24 #include "virt.h"
25
26 static struct ether_addr mac_addr = {
27 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
28 };
29
30 static bool verbose = true;
31
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] = { };
38
39 static int test_client_basic(sd_event *e) {
40 sd_dhcp6_client *client;
41
42 if (verbose)
43 printf("* %s\n", __FUNCTION__);
44
45 assert_se(sd_dhcp6_client_new(&client) >= 0);
46 assert_se(client);
47
48 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
49
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);
54
55 assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
56 sizeof (mac_addr),
57 ARPHRD_ETHER) >= 0);
58
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);
64
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);
71
72 assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
73
74 assert_se(sd_dhcp6_client_detach_event(client) >= 0);
75 assert_se(!sd_dhcp6_client_unref(client));
76
77 return 0;
78 }
79
80 static int test_option(sd_event *e) {
81 uint8_t packet[] = {
82 'F', 'O', 'O',
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',
87 'B', 'A', 'R',
88 };
89 uint8_t result[] = {
90 'F', 'O', 'O',
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,
94 'B', 'A', 'R',
95 };
96 uint16_t optcode;
97 size_t optlen;
98 uint8_t *optval, *buf, *out;
99 size_t zero = 0, pos = 3;
100 size_t buflen = sizeof(packet), outlen = sizeof(result);
101
102 if (verbose)
103 printf("* %s\n", __FUNCTION__);
104
105 assert_se(buflen == outlen);
106
107 assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
108 &optval) == -ENOMSG);
109
110 buflen -= 3;
111 buf = &packet[3];
112 outlen -= 3;
113 out = &result[3];
114
115 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
116 &optval) >= 0);
117 pos += 4 + 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));
122
123 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
124 optval) >= 0);
125 assert_se(out == &result[pos]);
126 assert_se(*out == 0x00);
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_VENDOR_CLASS);
133 assert_se(optlen == 9);
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 == 'B');
140
141 assert_se(memcmp(packet, result, sizeof(packet)) == 0);
142
143 return 0;
144 }
145
146 static int test_option_status(sd_event *e) {
147 uint8_t option1[] = {
148 /* IA NA */
149 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
150 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
151 /* status option */
152 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
153 };
154 static const uint8_t option2[] = {
155 /* IA NA */
156 0x00, 0x03, 0x00, 0x2e, 0x1a, 0x1d, 0x1a, 0x1d,
157 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
158 /* IA Addr */
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,
163 /* status option */
164 0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
165 };
166 static const uint8_t option3[] = {
167 /* IA NA */
168 0x00, 0x03, 0x00, 0x34, 0x1a, 0x1d, 0x1a, 0x1d,
169 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
170 /* IA Addr */
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,
175 /* status option */
176 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
177 'o', 'b', 'a', 'r',
178 };
179 static const uint8_t option4[] = {
180 /* IA PD */
181 0x00, 0x19, 0x00, 0x2f, 0x1a, 0x1d, 0x1a, 0x1d,
182 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
183 /* IA PD Prefix */
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,
188 0x00,
189 /* status option */
190 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
191 };
192 static const uint8_t option5[] = {
193 /* IA PD */
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,
201 0x00,
202 /* status option */
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,
209 0x00,
210 0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
211 };
212 DHCP6Option *option;
213 DHCP6IA ia, pd;
214 int r = 0;
215
216 if (verbose)
217 printf("* %s\n", __FUNCTION__);
218
219 zero(ia);
220 option = (DHCP6Option *)option1;
221 assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
222
223 r = dhcp6_option_parse_ia(option, &ia);
224 assert_se(r == -EINVAL);
225 assert_se(ia.addresses == NULL);
226
227 option->len = htobe16(17);
228 r = dhcp6_option_parse_ia(option, &ia);
229 assert_se(r == -ENOBUFS);
230 assert_se(ia.addresses == NULL);
231
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);
236
237 zero(ia);
238 option = (DHCP6Option *)option2;
239 assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
240
241 r = dhcp6_option_parse_ia(option, &ia);
242 assert_se(r >= 0);
243 assert_se(ia.addresses == NULL);
244
245 zero(ia);
246 option = (DHCP6Option *)option3;
247 assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
248
249 r = dhcp6_option_parse_ia(option, &ia);
250 assert_se(r >= 0);
251 assert_se(ia.addresses != NULL);
252 dhcp6_lease_free_ia(&ia);
253
254 zero(pd);
255 option = (DHCP6Option *)option4;
256 assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
257
258 r = dhcp6_option_parse_ia(option, &pd);
259 assert_se(r == 0);
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);
265
266 zero(pd);
267 option = (DHCP6Option *)option5;
268 assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
269
270 r = dhcp6_option_parse_ia(option, &pd);
271 assert_se(r == 0);
272 assert_se(pd.addresses != NULL);
273 dhcp6_lease_free_ia(&pd);
274
275 return 0;
276 }
277
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
304 };
305
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
329 };
330
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
334 };
335
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;
340 be32_t val;
341 uint8_t preference = 255;
342 struct in6_addr addr;
343 uint32_t lt_pref, lt_valid;
344 int r;
345 uint8_t *opt;
346 bool opt_clientid = false;
347 struct in6_addr *addrs;
348 char **domains;
349
350 if (verbose)
351 printf("* %s\n", __FUNCTION__);
352
353 assert_se(len >= sizeof(DHCP6Message));
354
355 assert_se(dhcp6_lease_new(&lease) >= 0);
356
357 assert_se(advertise->type == DHCP6_ADVERTISE);
358 assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) ==
359 0x0fb4e5);
360
361 while (pos < len) {
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;
366
367 switch(optcode) {
368 case SD_DHCP6_OPTION_CLIENTID:
369 assert_se(optlen == 14);
370
371 opt_clientid = true;
372 break;
373
374 case SD_DHCP6_OPTION_IA_NA:
375 assert_se(optlen == 94);
376 assert_se(!memcmp(optval, &msg_advertise[26], optlen));
377
378 val = htobe32(0x0ecfa37d);
379 assert_se(!memcmp(optval, &val, sizeof(val)));
380
381 val = htobe32(80);
382 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
383
384 val = htobe32(120);
385 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
386
387 assert_se(dhcp6_option_parse_ia(option, &lease->ia) >= 0);
388
389 break;
390
391 case SD_DHCP6_OPTION_SERVERID:
392 assert_se(optlen == 14);
393 assert_se(!memcmp(optval, &msg_advertise[179], optlen));
394
395 assert_se(dhcp6_lease_set_serverid(lease, optval,
396 optlen) >= 0);
397 break;
398
399 case SD_DHCP6_OPTION_PREFERENCE:
400 assert_se(optlen == 1);
401 assert_se(!*optval);
402
403 assert_se(dhcp6_lease_set_preference(lease,
404 *optval) >= 0);
405 break;
406
407 case SD_DHCP6_OPTION_ELAPSED_TIME:
408 assert_se(optlen == 2);
409
410 break;
411
412 case SD_DHCP6_OPTION_DNS_SERVERS:
413 assert_se(optlen == 16);
414 assert_se(dhcp6_lease_set_dns(lease, optval,
415 optlen) >= 0);
416 break;
417
418 case SD_DHCP6_OPTION_DOMAIN_LIST:
419 assert_se(optlen == 11);
420 assert_se(dhcp6_lease_set_domains(lease, optval,
421 optlen) >= 0);
422 break;
423
424 case SD_DHCP6_OPTION_SNTP_SERVERS:
425 assert_se(optlen == 16);
426 assert_se(dhcp6_lease_set_sntp(lease, optval,
427 optlen) >= 0);
428 break;
429
430 default:
431 break;
432 }
433
434 pos += sizeof(*option) + optlen;
435 }
436
437 assert_se(pos == len);
438 assert_se(opt_clientid);
439
440 sd_dhcp6_lease_reset_address_iter(lease);
441 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
442 &lt_valid) >= 0);
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, &lt_pref,
447 &lt_valid) == -ENOMSG);
448
449 sd_dhcp6_lease_reset_address_iter(lease);
450 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
451 &lt_valid) >= 0);
452 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
453 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
454 &lt_valid) == -ENOMSG);
455 sd_dhcp6_lease_reset_address_iter(lease);
456 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
457 &lt_valid) >= 0);
458 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
459 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
460 &lt_valid) == -ENOMSG);
461
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));
465
466 assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0);
467 assert_se(preference == 0);
468
469 r = sd_dhcp6_lease_get_dns(lease, &addrs);
470 assert_se(r == 1);
471 assert_se(!memcmp(addrs, &msg_advertise[124], r * 16));
472
473 r = sd_dhcp6_lease_get_domains(lease, &domains);
474 assert_se(r == 1);
475 assert_se(!strcmp("lab.intra", domains[0]));
476 assert_se(domains[1] == NULL);
477
478 r = sd_dhcp6_lease_get_ntp_addrs(lease, &addrs);
479 assert_se(r == 1);
480 assert_se(!memcmp(addrs, &msg_advertise[159], r * 16));
481
482 return 0;
483 }
484
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");
487
488 return 0;
489 }
490
491 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
492 void *userdata) {
493 sd_event *e = userdata;
494 sd_dhcp6_lease *lease;
495 struct in6_addr *addrs;
496 char **domains;
497
498 assert_se(e);
499 assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
500
501 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
502
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);
506
507 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
508 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
509
510 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
511 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
512
513 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
514
515 if (verbose)
516 printf(" got DHCPv6 event %d\n", event);
517
518 sd_event_exit(e, 0);
519 }
520
521 static int test_client_send_reply(DHCP6Message *request) {
522 DHCP6Message reply;
523
524 reply.transaction_id = request->transaction_id;
525 reply.type = DHCP6_REPLY;
526
527 memcpy(msg_reply, &reply.transaction_id, 4);
528
529 memcpy(&msg_reply[26], test_duid, sizeof(test_duid));
530
531 memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid));
532
533 assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply))
534 == sizeof(msg_reply));
535
536 return 0;
537 }
538
539 static int test_client_verify_request(DHCP6Message *request, size_t len) {
540 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
541 size_t pos = 0;
542 bool found_clientid = false, found_iana = false, found_serverid = false,
543 found_elapsed_time = false, found_fqdn = false;
544 struct in6_addr addr;
545 be32_t val;
546 uint32_t lt_pref, lt_valid;
547
548 assert_se(request->type == DHCP6_REQUEST);
549
550 assert_se(dhcp6_lease_new(&lease) >= 0);
551
552 len -= sizeof(DHCP6Message);
553
554 while (pos < len) {
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;
559
560 switch(optcode) {
561 case SD_DHCP6_OPTION_CLIENTID:
562 assert_se(!found_clientid);
563 found_clientid = true;
564
565 assert_se(!memcmp(optval, &test_duid,
566 sizeof(test_duid)));
567
568 break;
569
570 case SD_DHCP6_OPTION_IA_NA:
571 assert_se(!found_iana);
572 found_iana = true;
573
574 assert_se(optlen == 40);
575 assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
576
577 val = htobe32(80);
578 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
579
580 val = htobe32(120);
581 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
582
583 assert_se(!dhcp6_option_parse_ia(option, &lease->ia));
584
585 break;
586
587 case SD_DHCP6_OPTION_SERVERID:
588 assert_se(!found_serverid);
589 found_serverid = true;
590
591 assert_se(optlen == 14);
592 assert_se(!memcmp(&msg_advertise[179], optval, optlen));
593
594 break;
595
596 case SD_DHCP6_OPTION_ELAPSED_TIME:
597 assert_se(!found_elapsed_time);
598 found_elapsed_time = true;
599
600 assert_se(optlen == 2);
601
602 break;
603 case SD_DHCP6_OPTION_FQDN:
604 assert_se(!found_fqdn);
605 found_fqdn = true;
606
607 assert_se(optlen == 17);
608
609 assert_se(optval[0] == 0x01);
610 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
611 break;
612 }
613
614 pos += sizeof(*option) + optlen;
615 }
616
617 assert_se(found_clientid && found_iana && found_serverid &&
618 found_elapsed_time);
619
620 sd_dhcp6_lease_reset_address_iter(lease);
621 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
622 &lt_valid) >= 0);
623 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
624 assert_se(lt_pref == 150);
625 assert_se(lt_valid == 180);
626
627 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
628 &lt_valid) == -ENOMSG);
629
630 return 0;
631 }
632
633 static int test_client_send_advertise(DHCP6Message *solicit) {
634 DHCP6Message advertise;
635
636 advertise.transaction_id = solicit->transaction_id;
637 advertise.type = DHCP6_ADVERTISE;
638
639 memcpy(msg_advertise, &advertise.transaction_id, 4);
640
641 memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
642
643 memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
644
645 assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
646 == sizeof(msg_advertise));
647
648 return 0;
649 }
650
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;
654 size_t pos = 0;
655
656 assert_se(solicit->type == DHCP6_SOLICIT);
657
658 len -= sizeof(DHCP6Message);
659
660 while (pos < len) {
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;
665
666 switch(optcode) {
667 case SD_DHCP6_OPTION_CLIENTID:
668 assert_se(!found_clientid);
669 found_clientid = true;
670
671 assert_se(optlen == sizeof(test_duid));
672 memcpy(&test_duid, optval, sizeof(test_duid));
673
674 break;
675
676 case SD_DHCP6_OPTION_IA_NA:
677 assert_se(!found_iana);
678 found_iana = true;
679
680 assert_se(optlen == 12);
681
682 memcpy(&test_iaid, optval, sizeof(test_iaid));
683
684 break;
685
686 case SD_DHCP6_OPTION_ELAPSED_TIME:
687 assert_se(!found_elapsed_time);
688 found_elapsed_time = true;
689
690 assert_se(optlen == 2);
691
692 break;
693
694 case SD_DHCP6_OPTION_FQDN:
695 assert_se(!found_fqdn);
696 found_fqdn = true;
697
698 assert_se(optlen == 17);
699
700 assert_se(optval[0] == 0x01);
701 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
702
703 break;
704 }
705
706 pos += sizeof(*option) + optlen;
707 }
708
709 assert_se(pos == len);
710 assert_se(found_clientid && found_iana && found_elapsed_time);
711
712 return 0;
713 }
714
715 static void test_client_information_cb(sd_dhcp6_client *client, int event,
716 void *userdata) {
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 } } };
721 char **domains;
722
723 assert_se(e);
724 assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
725
726 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
727
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);
731
732 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
733 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
734
735 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
736 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
737
738 if (verbose)
739 printf(" got DHCPv6 event %d\n", event);
740
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);
745
746 assert_se(sd_dhcp6_client_set_callback(client,
747 test_client_solicit_cb, e) >= 0);
748
749 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
750
751 assert_se(sd_dhcp6_client_start(client) >= 0);
752
753 }
754
755 static int test_client_verify_information_request(DHCP6Message *information_request,
756 size_t len) {
757
758 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
759 size_t pos = 0;
760 bool found_clientid = false, found_elapsed_time = false;
761 struct in6_addr addr;
762 uint32_t lt_pref, lt_valid;
763
764 assert_se(information_request->type == DHCP6_INFORMATION_REQUEST);
765
766 assert_se(dhcp6_lease_new(&lease) >= 0);
767
768 len -= sizeof(DHCP6Message);
769
770 while (pos < len) {
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;
775
776 switch(optcode) {
777 case SD_DHCP6_OPTION_CLIENTID:
778 assert_se(!found_clientid);
779 found_clientid = true;
780
781 assert_se(optlen == sizeof(test_duid));
782 memcpy(&test_duid, optval, sizeof(test_duid));
783
784 break;
785
786 case SD_DHCP6_OPTION_IA_NA:
787 assert_not_reached("IA TA option must not be present");
788
789 break;
790
791 case SD_DHCP6_OPTION_SERVERID:
792 assert_not_reached("Server ID option must not be present");
793
794 break;
795
796 case SD_DHCP6_OPTION_ELAPSED_TIME:
797 assert_se(!found_elapsed_time);
798 found_elapsed_time = true;
799
800 assert_se(optlen == 2);
801
802 break;
803 }
804
805 pos += sizeof(*option) + optlen;
806 }
807
808 assert_se(pos == len);
809 assert_se(found_clientid && found_elapsed_time);
810
811 sd_dhcp6_lease_reset_address_iter(lease);
812
813 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
814 &lt_valid) == -ENOMSG);
815
816 return 0;
817 }
818
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;
824
825 assert_se(s == test_dhcp_fd[0]);
826 assert_se(server_address);
827 assert_se(packet);
828 assert_se(len > sizeof(DHCP6Message) + 4);
829
830 assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
831
832 message = (DHCP6Message *)packet;
833
834 assert_se(message->transaction_id & 0x00ffffff);
835
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++;
848 }
849
850 return len;
851 }
852
853 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
854 assert_se(index == test_index);
855
856 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
857 return -errno;
858
859 return test_dhcp_fd[0];
860 }
861
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 } } };
866 int val = true;
867
868 if (verbose)
869 printf("* %s\n", __FUNCTION__);
870
871 assert_se(sd_dhcp6_client_new(&client) >= 0);
872 assert_se(client);
873
874 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
875
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,
878 sizeof (mac_addr),
879 ARPHRD_ETHER) >= 0);
880 assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
881
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);
887
888 assert_se(sd_dhcp6_client_set_callback(client,
889 test_client_information_cb, e) >= 0);
890
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);
894
895 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
896
897 assert_se(sd_dhcp6_client_start(client) >= 0);
898
899 sd_event_loop(e);
900
901 hangcheck = sd_event_source_unref(hangcheck);
902
903 assert_se(!sd_dhcp6_client_unref(client));
904
905 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
906
907 return 0;
908 }
909
910 int main(int argc, char *argv[]) {
911 _cleanup_(sd_event_unrefp) sd_event *e;
912
913 assert_se(sd_event_new(&e) >= 0);
914
915 log_set_max_level(LOG_DEBUG);
916 log_parse_environment();
917 log_open();
918
919 test_client_basic(e);
920 test_option(e);
921 test_option_status(e);
922 test_advertise_option(e);
923 test_client_solicit(e);
924
925 return 0;
926 }