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