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