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