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