]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp6-client.c
Merge pull request #16556 from keszybz/test-terminal-colors
[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 "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 val = htobe32(80);
654 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
655
656 val = htobe32(120);
657 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
658
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,
698 &lt_valid) >= 0);
699 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
700 assert_se(lt_pref == 150);
701 assert_se(lt_valid == 180);
702
703 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
704 &lt_valid) == -ENOMSG);
705
706 return 0;
707 }
708
709 static int test_client_send_advertise(DHCP6Message *solicit) {
710 DHCP6Message advertise;
711
712 advertise.transaction_id = solicit->transaction_id;
713 advertise.type = DHCP6_ADVERTISE;
714
715 memcpy(msg_advertise, &advertise.transaction_id, 4);
716
717 memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
718
719 memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
720
721 assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
722 == sizeof(msg_advertise));
723
724 return 0;
725 }
726
727 static int test_client_verify_solicit(DHCP6Message *solicit, size_t len) {
728 bool found_clientid = false, found_iana = false,
729 found_elapsed_time = false, found_fqdn = false;
730 size_t pos = 0;
731
732 log_debug("/* %s */", __func__);
733
734 assert_se(solicit->type == DHCP6_SOLICIT);
735
736 len -= sizeof(DHCP6Message);
737
738 while (pos < len) {
739 DHCP6Option *option = (DHCP6Option *)&solicit->options[pos];
740 uint16_t optcode = be16toh(option->code);
741 uint16_t optlen = be16toh(option->len);
742 uint8_t *optval = option->data;
743
744 switch(optcode) {
745 case SD_DHCP6_OPTION_CLIENTID:
746 assert_se(!found_clientid);
747 found_clientid = true;
748
749 assert_se(optlen == sizeof(test_duid));
750 memcpy(&test_duid, optval, sizeof(test_duid));
751
752 break;
753
754 case SD_DHCP6_OPTION_IA_NA:
755 assert_se(!found_iana);
756 found_iana = true;
757
758 assert_se(optlen == 12);
759
760 memcpy(&test_iaid, optval, sizeof(test_iaid));
761
762 break;
763
764 case SD_DHCP6_OPTION_ELAPSED_TIME:
765 assert_se(!found_elapsed_time);
766 found_elapsed_time = true;
767
768 assert_se(optlen == 2);
769
770 break;
771
772 case SD_DHCP6_OPTION_FQDN:
773 assert_se(!found_fqdn);
774 found_fqdn = true;
775
776 assert_se(optlen == 17);
777
778 assert_se(optval[0] == 0x01);
779 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
780
781 break;
782 }
783
784 pos += sizeof(*option) + optlen;
785 }
786
787 assert_se(pos == len);
788 assert_se(found_clientid && found_iana && found_elapsed_time);
789
790 return 0;
791 }
792
793 static void test_client_information_cb(sd_dhcp6_client *client, int event,
794 void *userdata) {
795 sd_event *e = userdata;
796 sd_dhcp6_lease *lease;
797 const struct in6_addr *addrs;
798 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
799 char **domains;
800 const char *fqdn;
801
802 log_debug("/* %s */", __func__);
803
804 assert_se(e);
805 assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
806
807 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
808
809 assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1);
810 assert_se(!strcmp("lab.intra", domains[0]));
811 assert_se(domains[1] == NULL);
812
813 assert_se(sd_dhcp6_lease_get_fqdn(lease, &fqdn) >= 0);
814 assert_se(streq(fqdn, "client.intra"));
815
816 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
817 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
818
819 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
820 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
821
822 assert_se(sd_dhcp6_client_set_information_request(client, false) == -EBUSY);
823 assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0);
824 assert_se(sd_dhcp6_client_stop(client) >= 0);
825 assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0);
826
827 assert_se(sd_dhcp6_client_set_callback(client,
828 test_client_solicit_cb, e) >= 0);
829
830 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
831
832 assert_se(sd_dhcp6_client_start(client) >= 0);
833
834 }
835
836 static int test_client_verify_information_request(DHCP6Message *information_request,
837 size_t len) {
838
839 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
840 size_t pos = 0;
841 bool found_clientid = false, found_elapsed_time = false;
842 struct in6_addr addr;
843 uint32_t lt_pref, lt_valid;
844
845 log_debug("/* %s */", __func__);
846
847 assert_se(information_request->type == DHCP6_INFORMATION_REQUEST);
848 assert_se(dhcp6_lease_new(&lease) >= 0);
849
850 len -= sizeof(DHCP6Message);
851
852 while (pos < len) {
853 DHCP6Option *option = (DHCP6Option *)&information_request->options[pos];
854 uint16_t optcode = be16toh(option->code);
855 uint16_t optlen = be16toh(option->len);
856 uint8_t *optval = option->data;
857
858 switch(optcode) {
859 case SD_DHCP6_OPTION_CLIENTID:
860 assert_se(!found_clientid);
861 found_clientid = true;
862
863 assert_se(optlen == sizeof(test_duid));
864 memcpy(&test_duid, optval, sizeof(test_duid));
865
866 break;
867
868 case SD_DHCP6_OPTION_IA_NA:
869 assert_not_reached("IA TA option must not be present");
870
871 break;
872
873 case SD_DHCP6_OPTION_SERVERID:
874 assert_not_reached("Server ID option must not be present");
875
876 break;
877
878 case SD_DHCP6_OPTION_ELAPSED_TIME:
879 assert_se(!found_elapsed_time);
880 found_elapsed_time = true;
881
882 assert_se(optlen == 2);
883
884 break;
885 }
886
887 pos += sizeof(*option) + optlen;
888 }
889
890 assert_se(pos == len);
891 assert_se(found_clientid && found_elapsed_time);
892
893 sd_dhcp6_lease_reset_address_iter(lease);
894
895 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
896 &lt_valid) == -ENOMSG);
897
898 return 0;
899 }
900
901 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
902 const void *packet, size_t len) {
903 struct in6_addr mcast =
904 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
905 DHCP6Message *message;
906
907 assert_se(s == test_dhcp_fd[0]);
908 assert_se(server_address);
909 assert_se(packet);
910 assert_se(len > sizeof(DHCP6Message) + 4);
911 assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
912
913 message = (DHCP6Message *)packet;
914
915 assert_se(message->transaction_id & 0x00ffffff);
916
917 if (test_client_message_num == 0) {
918 test_client_verify_information_request(message, len);
919 test_client_send_reply(message);
920 test_client_message_num++;
921 } else if (test_client_message_num == 1) {
922 test_client_verify_solicit(message, len);
923 test_client_send_advertise(message);
924 test_client_message_num++;
925 } else if (test_client_message_num == 2) {
926 test_client_verify_request(message, len);
927 test_client_send_reply(message);
928 test_client_message_num++;
929 }
930
931 return len;
932 }
933
934 int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
935 assert_se(ifindex == test_ifindex);
936
937 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_dhcp_fd) < 0)
938 return -errno;
939
940 return test_dhcp_fd[0];
941 }
942
943 static int test_client_solicit(sd_event *e) {
944 sd_dhcp6_client *client;
945 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
946 int val;
947
948 log_debug("/* %s */", __func__);
949
950 assert_se(sd_dhcp6_client_new(&client) >= 0);
951 assert_se(client);
952
953 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
954
955 assert_se(sd_dhcp6_client_set_ifindex(client, test_ifindex) == 0);
956 assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
957 sizeof (mac_addr),
958 ARPHRD_ETHER) >= 0);
959 assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
960
961 assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
962 assert_se(val == 0);
963 assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
964 assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
965 assert_se(val);
966
967 assert_se(sd_dhcp6_client_set_callback(client,
968 test_client_information_cb, e) >= 0);
969
970 assert_se(sd_event_add_time_relative(e, &hangcheck, clock_boottime_or_monotonic(),
971 2 * USEC_PER_SEC, 0,
972 test_hangcheck, NULL) >= 0);
973
974 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
975
976 assert_se(sd_dhcp6_client_start(client) >= 0);
977
978 sd_event_loop(e);
979
980 hangcheck = sd_event_source_unref(hangcheck);
981
982 assert_se(!sd_dhcp6_client_unref(client));
983
984 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
985
986 return 0;
987 }
988
989 int main(int argc, char *argv[]) {
990 _cleanup_(sd_event_unrefp) sd_event *e;
991
992 assert_se(sd_event_new(&e) >= 0);
993
994 test_setup_logging(LOG_DEBUG);
995
996 test_client_basic(e);
997 test_option(e);
998 test_option_status(e);
999 test_advertise_option(e);
1000 test_client_solicit(e);
1001 test_parse_domain(e);
1002
1003 return 0;
1004 }