]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp6-client.c
Merge pull request #18777 from yuwata/network-set-ifname-to-engines
[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(NULL, 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(NULL, 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(NULL, 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(NULL, 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(NULL, 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(NULL, 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(NULL, 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(optval == &msg_advertise[26]);
453 assert_se(!memcmp(optval, &msg_advertise[26], optlen));
454
455 val = htobe32(0x0ecfa37d);
456 assert_se(!memcmp(optval, &val, sizeof(val)));
457
458 val = htobe32(80);
459 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
460
461 val = htobe32(120);
462 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
463
464 assert_se(dhcp6_option_parse_ia(NULL, option, &lease->ia, NULL) >= 0);
465
466 break;
467
468 case SD_DHCP6_OPTION_SERVERID:
469 assert_se(optlen == 14);
470 assert_se(optval == &msg_advertise[179]);
471 assert_se(!memcmp(optval, &msg_advertise[179], optlen));
472
473 assert_se(dhcp6_lease_set_serverid(lease, optval,
474 optlen) >= 0);
475 break;
476
477 case SD_DHCP6_OPTION_PREFERENCE:
478 assert_se(optlen == 1);
479 assert_se(!*optval);
480
481 assert_se(dhcp6_lease_set_preference(lease,
482 *optval) >= 0);
483 break;
484
485 case SD_DHCP6_OPTION_ELAPSED_TIME:
486 assert_se(optlen == 2);
487
488 break;
489
490 case SD_DHCP6_OPTION_DNS_SERVERS:
491 assert_se(optlen == 16);
492 assert_se(dhcp6_lease_set_dns(lease, optval,
493 optlen) >= 0);
494 break;
495
496 case SD_DHCP6_OPTION_DOMAIN_LIST:
497 assert_se(optlen == 11);
498 assert_se(dhcp6_lease_set_domains(lease, optval,
499 optlen) >= 0);
500 break;
501
502 case SD_DHCP6_OPTION_SNTP_SERVERS:
503 assert_se(optlen == 16);
504 assert_se(dhcp6_lease_set_sntp(lease, optval,
505 optlen) >= 0);
506 break;
507
508 default:
509 break;
510 }
511
512 pos += sizeof(*option) + optlen;
513 }
514
515 assert_se(pos == len);
516 assert_se(opt_clientid);
517
518 sd_dhcp6_lease_reset_address_iter(lease);
519 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
520 &lt_valid) >= 0);
521 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
522 assert_se(lt_pref == 150);
523 assert_se(lt_valid == 180);
524 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
525 &lt_valid) == -ENOMSG);
526
527 sd_dhcp6_lease_reset_address_iter(lease);
528 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
529 &lt_valid) >= 0);
530 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
531 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
532 &lt_valid) == -ENOMSG);
533 sd_dhcp6_lease_reset_address_iter(lease);
534 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
535 &lt_valid) >= 0);
536 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
537 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
538 &lt_valid) == -ENOMSG);
539
540 assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0);
541 assert_se(len == 14);
542 assert_se(!memcmp(opt, &msg_advertise[179], len));
543
544 assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0);
545 assert_se(preference == 0);
546
547 r = sd_dhcp6_lease_get_dns(lease, &addrs);
548 assert_se(r == 1);
549 assert_se(!memcmp(addrs, &msg_advertise[124], r * 16));
550
551 r = sd_dhcp6_lease_get_domains(lease, &domains);
552 assert_se(r == 1);
553 assert_se(!strcmp("lab.intra", domains[0]));
554 assert_se(domains[1] == NULL);
555
556 r = sd_dhcp6_lease_get_ntp_addrs(lease, &addrs);
557 assert_se(r == 1);
558 assert_se(!memcmp(addrs, &msg_advertise[159], r * 16));
559
560 return 0;
561 }
562
563 static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
564 assert_not_reached("Test case should have completed in 2 seconds");
565
566 return 0;
567 }
568
569 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
570 void *userdata) {
571 sd_event *e = userdata;
572 sd_dhcp6_lease *lease;
573 const struct in6_addr *addrs;
574 char **domains;
575
576 log_debug("/* %s */", __func__);
577
578 assert_se(e);
579 assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
580
581 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
582
583 assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1);
584 assert_se(!strcmp("lab.intra", domains[0]));
585 assert_se(domains[1] == NULL);
586
587 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
588 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
589
590 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
591 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
592
593 assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
594
595 sd_event_exit(e, 0);
596 }
597
598 static int test_client_send_reply(DHCP6Message *request) {
599 DHCP6Message reply;
600
601 reply.transaction_id = request->transaction_id;
602 reply.type = DHCP6_REPLY;
603
604 memcpy(msg_reply, &reply.transaction_id, 4);
605
606 memcpy(&msg_reply[26], test_duid, sizeof(test_duid));
607
608 memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid));
609
610 assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply))
611 == sizeof(msg_reply));
612
613 return 0;
614 }
615
616 static int test_client_verify_request(DHCP6Message *request, size_t len) {
617 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
618 bool found_clientid = false, found_iana = false, found_serverid = false,
619 found_elapsed_time = false, found_fqdn = false;
620 uint32_t lt_pref, lt_valid;
621 struct in6_addr addr;
622 size_t pos = 0;
623 be32_t val;
624
625 log_debug("/* %s */", __func__);
626
627 assert_se(request->type == DHCP6_REQUEST);
628 assert_se(dhcp6_lease_new(&lease) >= 0);
629
630 len -= sizeof(DHCP6Message);
631
632 while (pos < len) {
633 DHCP6Option *option = (DHCP6Option *)&request->options[pos];
634 uint16_t optcode = be16toh(option->code);
635 uint16_t optlen = be16toh(option->len);
636 uint8_t *optval = option->data;
637
638 switch(optcode) {
639 case SD_DHCP6_OPTION_CLIENTID:
640 assert_se(!found_clientid);
641 found_clientid = true;
642
643 assert_se(!memcmp(optval, &test_duid,
644 sizeof(test_duid)));
645
646 break;
647
648 case SD_DHCP6_OPTION_IA_NA:
649 assert_se(!found_iana);
650 found_iana = true;
651
652 assert_se(optlen == 40);
653 assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
654
655 /* T1 and T2 should not be set. */
656 val = 0;
657 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
658 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
659
660 /* Then, this should refuse all addresses. */
661 assert_se(dhcp6_option_parse_ia(NULL, option, &lease->ia, NULL) >= 0);
662
663 break;
664
665 case SD_DHCP6_OPTION_SERVERID:
666 assert_se(!found_serverid);
667 found_serverid = true;
668
669 assert_se(optlen == 14);
670 assert_se(!memcmp(&msg_advertise[179], optval, optlen));
671
672 break;
673
674 case SD_DHCP6_OPTION_ELAPSED_TIME:
675 assert_se(!found_elapsed_time);
676 found_elapsed_time = true;
677
678 assert_se(optlen == 2);
679
680 break;
681 case SD_DHCP6_OPTION_FQDN:
682 assert_se(!found_fqdn);
683 found_fqdn = true;
684
685 assert_se(optlen == 17);
686
687 assert_se(optval[0] == 0x01);
688 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
689 break;
690 }
691
692 pos += sizeof(*option) + optlen;
693 }
694
695 assert_se(found_clientid && found_iana && found_serverid &&
696 found_elapsed_time);
697
698 sd_dhcp6_lease_reset_address_iter(lease);
699 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref, &lt_valid) == -ENOMSG);
700
701 return 0;
702 }
703
704 static int test_client_send_advertise(DHCP6Message *solicit) {
705 DHCP6Message advertise;
706
707 advertise.transaction_id = solicit->transaction_id;
708 advertise.type = DHCP6_ADVERTISE;
709
710 memcpy(msg_advertise, &advertise.transaction_id, 4);
711
712 memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
713
714 memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
715
716 assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
717 == sizeof(msg_advertise));
718
719 return 0;
720 }
721
722 static int test_client_verify_solicit(DHCP6Message *solicit, size_t len) {
723 bool found_clientid = false, found_iana = false,
724 found_elapsed_time = false, found_fqdn = false;
725 size_t pos = 0;
726
727 log_debug("/* %s */", __func__);
728
729 assert_se(solicit->type == DHCP6_SOLICIT);
730
731 len -= sizeof(DHCP6Message);
732
733 while (pos < len) {
734 DHCP6Option *option = (DHCP6Option *)&solicit->options[pos];
735 uint16_t optcode = be16toh(option->code);
736 uint16_t optlen = be16toh(option->len);
737 uint8_t *optval = option->data;
738
739 switch(optcode) {
740 case SD_DHCP6_OPTION_CLIENTID:
741 assert_se(!found_clientid);
742 found_clientid = true;
743
744 assert_se(optlen == sizeof(test_duid));
745 memcpy(&test_duid, optval, sizeof(test_duid));
746
747 break;
748
749 case SD_DHCP6_OPTION_IA_NA:
750 assert_se(!found_iana);
751 found_iana = true;
752
753 assert_se(optlen == 12);
754
755 memcpy(&test_iaid, optval, sizeof(test_iaid));
756
757 break;
758
759 case SD_DHCP6_OPTION_ELAPSED_TIME:
760 assert_se(!found_elapsed_time);
761 found_elapsed_time = true;
762
763 assert_se(optlen == 2);
764
765 break;
766
767 case SD_DHCP6_OPTION_FQDN:
768 assert_se(!found_fqdn);
769 found_fqdn = true;
770
771 assert_se(optlen == 17);
772
773 assert_se(optval[0] == 0x01);
774 assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire)));
775
776 break;
777 }
778
779 pos += sizeof(*option) + optlen;
780 }
781
782 assert_se(pos == len);
783 assert_se(found_clientid && found_iana && found_elapsed_time);
784
785 return 0;
786 }
787
788 static void test_client_information_cb(sd_dhcp6_client *client, int event,
789 void *userdata) {
790 sd_event *e = userdata;
791 sd_dhcp6_lease *lease;
792 const struct in6_addr *addrs;
793 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
794 char **domains;
795 const char *fqdn;
796
797 log_debug("/* %s */", __func__);
798
799 assert_se(e);
800 assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
801
802 assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
803
804 assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1);
805 assert_se(!strcmp("lab.intra", domains[0]));
806 assert_se(domains[1] == NULL);
807
808 assert_se(sd_dhcp6_lease_get_fqdn(lease, &fqdn) >= 0);
809 assert_se(streq(fqdn, "client.intra"));
810
811 assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1);
812 assert_se(!memcmp(addrs, &msg_advertise[124], 16));
813
814 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1);
815 assert_se(!memcmp(addrs, &msg_advertise[159], 16));
816
817 assert_se(sd_dhcp6_client_set_information_request(client, false) == -EBUSY);
818 assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0);
819 assert_se(sd_dhcp6_client_stop(client) >= 0);
820 assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0);
821
822 assert_se(sd_dhcp6_client_set_callback(client,
823 test_client_solicit_cb, e) >= 0);
824
825 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
826
827 assert_se(sd_dhcp6_client_start(client) >= 0);
828
829 }
830
831 static int test_client_verify_information_request(DHCP6Message *information_request,
832 size_t len) {
833
834 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
835 size_t pos = 0;
836 bool found_clientid = false, found_elapsed_time = false;
837 struct in6_addr addr;
838 uint32_t lt_pref, lt_valid;
839
840 log_debug("/* %s */", __func__);
841
842 assert_se(information_request->type == DHCP6_INFORMATION_REQUEST);
843 assert_se(dhcp6_lease_new(&lease) >= 0);
844
845 len -= sizeof(DHCP6Message);
846
847 while (pos < len) {
848 DHCP6Option *option = (DHCP6Option *)&information_request->options[pos];
849 uint16_t optcode = be16toh(option->code);
850 uint16_t optlen = be16toh(option->len);
851 uint8_t *optval = option->data;
852
853 switch(optcode) {
854 case SD_DHCP6_OPTION_CLIENTID:
855 assert_se(!found_clientid);
856 found_clientid = true;
857
858 assert_se(optlen == sizeof(test_duid));
859 memcpy(&test_duid, optval, sizeof(test_duid));
860
861 break;
862
863 case SD_DHCP6_OPTION_IA_NA:
864 assert_not_reached("IA TA option must not be present");
865
866 break;
867
868 case SD_DHCP6_OPTION_SERVERID:
869 assert_not_reached("Server ID option must not be present");
870
871 break;
872
873 case SD_DHCP6_OPTION_ELAPSED_TIME:
874 assert_se(!found_elapsed_time);
875 found_elapsed_time = true;
876
877 assert_se(optlen == 2);
878
879 break;
880 }
881
882 pos += sizeof(*option) + optlen;
883 }
884
885 assert_se(pos == len);
886 assert_se(found_clientid && found_elapsed_time);
887
888 sd_dhcp6_lease_reset_address_iter(lease);
889
890 assert_se(sd_dhcp6_lease_get_address(lease, &addr, &lt_pref,
891 &lt_valid) == -ENOMSG);
892
893 return 0;
894 }
895
896 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
897 const void *packet, size_t len) {
898 struct in6_addr mcast =
899 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
900 DHCP6Message *message;
901
902 assert_se(s == test_dhcp_fd[0]);
903 assert_se(server_address);
904 assert_se(packet);
905 assert_se(len > sizeof(DHCP6Message) + 4);
906 assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
907
908 message = (DHCP6Message *)packet;
909
910 assert_se(message->transaction_id & 0x00ffffff);
911
912 if (test_client_message_num == 0) {
913 test_client_verify_information_request(message, len);
914 test_client_send_reply(message);
915 test_client_message_num++;
916 } else if (test_client_message_num == 1) {
917 test_client_verify_solicit(message, len);
918 test_client_send_advertise(message);
919 test_client_message_num++;
920 } else if (test_client_message_num == 2) {
921 test_client_verify_request(message, len);
922 test_client_send_reply(message);
923 test_client_message_num++;
924 }
925
926 return len;
927 }
928
929 int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
930 assert_se(ifindex == test_ifindex);
931
932 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_dhcp_fd) < 0)
933 return -errno;
934
935 return test_dhcp_fd[0];
936 }
937
938 static int test_client_solicit(sd_event *e) {
939 sd_dhcp6_client *client;
940 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
941 int val;
942
943 log_debug("/* %s */", __func__);
944
945 assert_se(sd_dhcp6_client_new(&client) >= 0);
946 assert_se(client);
947
948 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
949
950 assert_se(sd_dhcp6_client_set_ifindex(client, test_ifindex) == 0);
951 assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
952 sizeof (mac_addr),
953 ARPHRD_ETHER) >= 0);
954 assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
955
956 assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
957 assert_se(val == 0);
958 assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
959 assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
960 assert_se(val);
961
962 assert_se(sd_dhcp6_client_set_callback(client,
963 test_client_information_cb, e) >= 0);
964
965 assert_se(sd_event_add_time_relative(e, &hangcheck, clock_boottime_or_monotonic(),
966 2 * USEC_PER_SEC, 0,
967 test_hangcheck, NULL) >= 0);
968
969 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
970
971 assert_se(sd_dhcp6_client_start(client) >= 0);
972
973 sd_event_loop(e);
974
975 hangcheck = sd_event_source_unref(hangcheck);
976
977 assert_se(!sd_dhcp6_client_unref(client));
978
979 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
980
981 return 0;
982 }
983
984 int main(int argc, char *argv[]) {
985 _cleanup_(sd_event_unrefp) sd_event *e;
986
987 assert_se(sd_event_new(&e) >= 0);
988
989 test_setup_logging(LOG_DEBUG);
990
991 test_client_basic(e);
992 test_option(e);
993 test_option_status(e);
994 test_advertise_option(e);
995 test_client_solicit(e);
996 test_parse_domain(e);
997
998 return 0;
999 }