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