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