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