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