]>
Commit | Line | Data |
---|---|---|
813e3a6f PF |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright (C) 2014 Intel Corporation. All rights reserved. | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
07630cea | 22 | #include <net/ethernet.h> |
813e3a6f PF |
23 | #include <stdbool.h> |
24 | #include <stdio.h> | |
2ea8857e | 25 | #include <sys/socket.h> |
07630cea | 26 | #include <sys/types.h> |
2ea8857e | 27 | #include <unistd.h> |
813e3a6f | 28 | |
07630cea | 29 | #include "sd-dhcp6-client.h" |
813e3a6f | 30 | #include "sd-event.h" |
813e3a6f | 31 | |
f12ed3bf | 32 | #include "dhcp6-internal.h" |
859cca44 | 33 | #include "dhcp6-lease-internal.h" |
07630cea LP |
34 | #include "dhcp6-protocol.h" |
35 | #include "event-util.h" | |
36 | #include "macro.h" | |
37 | #include "socket-util.h" | |
38 | #include "virt.h" | |
813e3a6f PF |
39 | |
40 | static struct ether_addr mac_addr = { | |
41 | .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} | |
42 | }; | |
43 | ||
c4e8cedd | 44 | static bool verbose = true; |
813e3a6f | 45 | |
2ea8857e PF |
46 | static sd_event_source *hangcheck; |
47 | static int test_dhcp_fd[2]; | |
48 | static int test_index = 42; | |
5e256ea7 PF |
49 | static int test_client_message_num; |
50 | static be32_t test_iaid = 0; | |
51 | static uint8_t test_duid[14] = { }; | |
2ea8857e | 52 | |
813e3a6f PF |
53 | static int test_client_basic(sd_event *e) { |
54 | sd_dhcp6_client *client; | |
55 | ||
56 | if (verbose) | |
57 | printf("* %s\n", __FUNCTION__); | |
58 | ||
59 | assert_se(sd_dhcp6_client_new(&client) >= 0); | |
60 | assert_se(client); | |
61 | ||
62 | assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); | |
63 | ||
64 | assert_se(sd_dhcp6_client_set_index(client, 15) == 0); | |
65 | assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL); | |
66 | assert_se(sd_dhcp6_client_set_index(client, -1) == 0); | |
67 | assert_se(sd_dhcp6_client_set_index(client, 42) >= 0); | |
68 | ||
76253e73 DW |
69 | assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr, |
70 | sizeof (mac_addr), | |
71 | ARPHRD_ETHER) >= 0); | |
813e3a6f | 72 | |
da6fe470 PF |
73 | assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL); |
74 | assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST); | |
75 | assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST); | |
41e4615d | 76 | assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == -EEXIST); |
da6fe470 PF |
77 | assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST); |
78 | assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL); | |
79 | ||
813e3a6f PF |
80 | assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0); |
81 | ||
82 | assert_se(sd_dhcp6_client_detach_event(client) >= 0); | |
83 | assert_se(!sd_dhcp6_client_unref(client)); | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
f12ed3bf PF |
88 | static int test_option(sd_event *e) { |
89 | uint8_t packet[] = { | |
90 | 'F', 'O', 'O', | |
91 | 0x00, DHCP6_OPTION_ORO, 0x00, 0x07, | |
92 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', | |
93 | 0x00, DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09, | |
94 | '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
95 | 'B', 'A', 'R', | |
96 | }; | |
97 | uint8_t result[] = { | |
98 | 'F', 'O', 'O', | |
99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
102 | 'B', 'A', 'R', | |
103 | }; | |
104 | uint16_t optcode; | |
105 | size_t optlen; | |
106 | uint8_t *optval, *buf, *out; | |
107 | size_t zero = 0, pos = 3; | |
108 | size_t buflen = sizeof(packet), outlen = sizeof(result); | |
109 | ||
110 | if (verbose) | |
111 | printf("* %s\n", __FUNCTION__); | |
112 | ||
113 | assert_se(buflen == outlen); | |
114 | ||
115 | assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen, | |
116 | &optval) == -ENOMSG); | |
117 | ||
118 | buflen -= 3; | |
119 | buf = &packet[3]; | |
120 | outlen -= 3; | |
121 | out = &result[3]; | |
122 | ||
123 | assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen, | |
124 | &optval) >= 0); | |
125 | pos += 4 + optlen; | |
126 | assert_se(buf == &packet[pos]); | |
127 | assert_se(optcode == DHCP6_OPTION_ORO); | |
128 | assert_se(optlen == 7); | |
129 | assert_se(buflen + pos == sizeof(packet)); | |
130 | ||
131 | assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen, | |
132 | optval) >= 0); | |
133 | assert_se(out == &result[pos]); | |
134 | assert_se(*out == 0x00); | |
135 | ||
136 | assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen, | |
137 | &optval) >= 0); | |
138 | pos += 4 + optlen; | |
139 | assert_se(buf == &packet[pos]); | |
140 | assert_se(optcode == DHCP6_OPTION_VENDOR_CLASS); | |
141 | assert_se(optlen == 9); | |
142 | assert_se(buflen + pos == sizeof(packet)); | |
143 | ||
144 | assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen, | |
145 | optval) >= 0); | |
146 | assert_se(out == &result[pos]); | |
147 | assert_se(*out == 'B'); | |
148 | ||
149 | assert_se(memcmp(packet, result, sizeof(packet)) == 0); | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
859cca44 PF |
154 | static uint8_t msg_advertise[198] = { |
155 | 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e, | |
156 | 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30, | |
157 | 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03, | |
158 | 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00, | |
159 | 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05, | |
160 | 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, | |
161 | 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c, | |
162 | 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, | |
163 | 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00, | |
164 | 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28, | |
165 | 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65, | |
166 | 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65, | |
167 | 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66, | |
168 | 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e, | |
169 | 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68, | |
170 | 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, | |
171 | 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, | |
172 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, | |
173 | 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, | |
174 | 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, | |
175 | 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, | |
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, | |
177 | 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19, | |
178 | 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, | |
179 | 0x53, 0x00, 0x07, 0x00, 0x01, 0x00 | |
180 | }; | |
181 | ||
947527f8 PF |
182 | static uint8_t msg_reply[173] = { |
183 | 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e, | |
184 | 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53, | |
185 | 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01, | |
186 | 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, | |
187 | 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, | |
188 | 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d, | |
189 | 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, | |
190 | 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, | |
191 | 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, | |
192 | 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, | |
193 | 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e, | |
194 | 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64, | |
195 | 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, | |
196 | 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73, | |
197 | 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17, | |
198 | 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, | |
199 | 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
200 | 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c, | |
201 | 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61, | |
202 | 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d, | |
203 | 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, | |
204 | 0x00, 0x00, 0x00, 0x00, 0x01 | |
205 | }; | |
206 | ||
859cca44 PF |
207 | static int test_advertise_option(sd_event *e) { |
208 | _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; | |
209 | DHCP6Message *advertise = (DHCP6Message *)msg_advertise; | |
44481a8b | 210 | uint8_t *optval, *opt = msg_advertise + sizeof(DHCP6Message); |
859cca44 | 211 | uint16_t optcode; |
d182960a | 212 | size_t optlen, len = sizeof(msg_advertise) - sizeof(DHCP6Message); |
859cca44 PF |
213 | be32_t val; |
214 | uint8_t preference = 255; | |
215 | struct in6_addr addr; | |
216 | uint32_t lt_pref, lt_valid; | |
217 | int r; | |
218 | bool opt_clientid = false; | |
bc152ff8 PF |
219 | struct in6_addr *addrs; |
220 | char **domains; | |
859cca44 PF |
221 | |
222 | if (verbose) | |
223 | printf("* %s\n", __FUNCTION__); | |
224 | ||
225 | assert_se(dhcp6_lease_new(&lease) >= 0); | |
226 | ||
227 | assert_se(advertise->type == DHCP6_ADVERTISE); | |
228 | assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) == | |
229 | 0x0fb4e5); | |
230 | ||
231 | while ((r = dhcp6_option_parse(&opt, &len, &optcode, &optlen, | |
232 | &optval)) >= 0) { | |
233 | ||
234 | switch(optcode) { | |
235 | case DHCP6_OPTION_CLIENTID: | |
236 | assert_se(optlen == 14); | |
237 | ||
238 | opt_clientid = true; | |
239 | break; | |
240 | ||
241 | case DHCP6_OPTION_IA_NA: | |
242 | assert_se(optlen == 94); | |
243 | assert_se(!memcmp(optval, &msg_advertise[26], optlen)); | |
244 | ||
245 | val = htobe32(0x0ecfa37d); | |
246 | assert_se(!memcmp(optval, &val, sizeof(val))); | |
247 | ||
248 | val = htobe32(80); | |
249 | assert_se(!memcmp(optval + 4, &val, sizeof(val))); | |
250 | ||
251 | val = htobe32(120); | |
252 | assert_se(!memcmp(optval + 8, &val, sizeof(val))); | |
253 | ||
254 | assert_se(dhcp6_option_parse_ia(&optval, &optlen, | |
255 | optcode, | |
256 | &lease->ia) >= 0); | |
257 | ||
258 | break; | |
259 | ||
260 | case DHCP6_OPTION_SERVERID: | |
261 | assert_se(optlen == 14); | |
262 | assert_se(!memcmp(optval, &msg_advertise[179], optlen)); | |
263 | ||
264 | assert_se(dhcp6_lease_set_serverid(lease, optval, | |
265 | optlen) >= 0); | |
266 | break; | |
267 | ||
268 | case DHCP6_OPTION_PREFERENCE: | |
269 | assert_se(optlen == 1); | |
270 | assert_se(!*optval); | |
271 | ||
272 | assert_se(dhcp6_lease_set_preference(lease, | |
273 | *optval) >= 0); | |
274 | break; | |
275 | ||
d63be95a PF |
276 | case DHCP6_OPTION_ELAPSED_TIME: |
277 | assert_se(optlen == 2); | |
278 | ||
279 | break; | |
280 | ||
bc152ff8 PF |
281 | case DHCP6_OPTION_DNS_SERVERS: |
282 | assert_se(optlen == 16); | |
283 | assert_se(dhcp6_lease_set_dns(lease, optval, | |
284 | optlen) >= 0); | |
285 | break; | |
286 | ||
287 | case DHCP6_OPTION_DOMAIN_LIST: | |
288 | assert_se(optlen == 11); | |
289 | assert_se(dhcp6_lease_set_domains(lease, optval, | |
290 | optlen) >= 0); | |
291 | break; | |
292 | ||
293 | case DHCP6_OPTION_SNTP_SERVERS: | |
294 | assert_se(optlen == 16); | |
295 | assert_se(dhcp6_lease_set_sntp(lease, optval, | |
296 | optlen) >= 0); | |
297 | break; | |
298 | ||
859cca44 PF |
299 | default: |
300 | break; | |
301 | } | |
302 | } | |
303 | ||
304 | ||
305 | assert_se(r == -ENOMSG); | |
306 | ||
307 | assert_se(opt_clientid); | |
308 | ||
e7504d95 PF |
309 | sd_dhcp6_lease_reset_address_iter(lease); |
310 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, | |
311 | <_valid) >= 0); | |
859cca44 PF |
312 | assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); |
313 | assert_se(lt_pref == 150); | |
314 | assert_se(lt_valid == 180); | |
e7504d95 PF |
315 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, |
316 | <_valid) == -ENOMSG); | |
859cca44 | 317 | |
e7504d95 PF |
318 | sd_dhcp6_lease_reset_address_iter(lease); |
319 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, | |
320 | <_valid) >= 0); | |
859cca44 | 321 | assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); |
e7504d95 PF |
322 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, |
323 | <_valid) == -ENOMSG); | |
324 | sd_dhcp6_lease_reset_address_iter(lease); | |
325 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, | |
326 | <_valid) >= 0); | |
859cca44 | 327 | assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); |
e7504d95 PF |
328 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, |
329 | <_valid) == -ENOMSG); | |
859cca44 PF |
330 | |
331 | assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0); | |
332 | assert_se(len == 14); | |
333 | assert_se(!memcmp(opt, &msg_advertise[179], len)); | |
334 | ||
335 | assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0); | |
336 | assert_se(preference == 0); | |
337 | ||
bc152ff8 PF |
338 | r = sd_dhcp6_lease_get_dns(lease, &addrs); |
339 | assert_se(r == 1); | |
340 | assert_se(!memcmp(addrs, &msg_advertise[124], r * 16)); | |
341 | ||
342 | r = sd_dhcp6_lease_get_domains(lease, &domains); | |
343 | assert_se(r == 1); | |
344 | assert_se(!strcmp("lab.intra", domains[0])); | |
345 | assert_se(domains[1] == NULL); | |
346 | ||
347 | r = sd_dhcp6_lease_get_ntp_addrs(lease, &addrs); | |
348 | assert_se(r == 1); | |
349 | assert_se(!memcmp(addrs, &msg_advertise[159], r * 16)); | |
350 | ||
859cca44 PF |
351 | return 0; |
352 | } | |
353 | ||
2ea8857e PF |
354 | static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) { |
355 | assert_not_reached("Test case should have completed in 2 seconds"); | |
356 | ||
357 | return 0; | |
358 | } | |
359 | ||
c4e8cedd PF |
360 | static void test_client_solicit_cb(sd_dhcp6_client *client, int event, |
361 | void *userdata) { | |
362 | sd_event *e = userdata; | |
bc152ff8 PF |
363 | sd_dhcp6_lease *lease; |
364 | struct in6_addr *addrs; | |
365 | char **domains; | |
2ea8857e | 366 | |
c4e8cedd | 367 | assert_se(e); |
10c9ce61 | 368 | assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE); |
2ea8857e | 369 | |
bc152ff8 PF |
370 | assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); |
371 | ||
372 | assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1); | |
373 | assert_se(!strcmp("lab.intra", domains[0])); | |
374 | assert_se(domains[1] == NULL); | |
375 | ||
376 | assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1); | |
377 | assert_se(!memcmp(addrs, &msg_advertise[124], 16)); | |
378 | ||
379 | assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); | |
380 | assert_se(!memcmp(addrs, &msg_advertise[159], 16)); | |
381 | ||
c4e8cedd PF |
382 | assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY); |
383 | ||
384 | if (verbose) | |
385 | printf(" got DHCPv6 event %d\n", event); | |
386 | ||
387 | sd_event_exit(e, 0); | |
2ea8857e PF |
388 | } |
389 | ||
5e256ea7 | 390 | static int test_client_send_reply(DHCP6Message *request) { |
947527f8 PF |
391 | DHCP6Message reply; |
392 | ||
393 | reply.transaction_id = request->transaction_id; | |
394 | reply.type = DHCP6_REPLY; | |
395 | ||
396 | memcpy(msg_reply, &reply.transaction_id, 4); | |
397 | ||
398 | memcpy(&msg_reply[26], test_duid, sizeof(test_duid)); | |
399 | ||
400 | memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid)); | |
401 | ||
402 | assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply)) | |
403 | == sizeof(msg_reply)); | |
404 | ||
5e256ea7 PF |
405 | return 0; |
406 | } | |
407 | ||
408 | static int test_client_verify_request(DHCP6Message *request, uint8_t *option, | |
409 | size_t len) { | |
410 | _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; | |
411 | uint8_t *optval; | |
412 | uint16_t optcode; | |
413 | size_t optlen; | |
d63be95a PF |
414 | bool found_clientid = false, found_iana = false, found_serverid = false, |
415 | found_elapsed_time = false; | |
5e256ea7 PF |
416 | int r; |
417 | struct in6_addr addr; | |
418 | be32_t val; | |
419 | uint32_t lt_pref, lt_valid; | |
420 | ||
421 | assert_se(request->type == DHCP6_REQUEST); | |
422 | ||
423 | assert_se(dhcp6_lease_new(&lease) >= 0); | |
424 | ||
425 | while ((r = dhcp6_option_parse(&option, &len, | |
426 | &optcode, &optlen, &optval)) >= 0) { | |
427 | switch(optcode) { | |
428 | case DHCP6_OPTION_CLIENTID: | |
429 | assert_se(!found_clientid); | |
430 | found_clientid = true; | |
431 | ||
432 | assert_se(!memcmp(optval, &test_duid, | |
433 | sizeof(test_duid))); | |
434 | ||
435 | break; | |
436 | ||
437 | case DHCP6_OPTION_IA_NA: | |
438 | assert_se(!found_iana); | |
439 | found_iana = true; | |
440 | ||
441 | ||
442 | assert_se(optlen == 40); | |
443 | assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid))); | |
444 | ||
445 | val = htobe32(80); | |
446 | assert_se(!memcmp(optval + 4, &val, sizeof(val))); | |
447 | ||
448 | val = htobe32(120); | |
449 | assert_se(!memcmp(optval + 8, &val, sizeof(val))); | |
450 | ||
451 | assert_se(!dhcp6_option_parse_ia(&optval, &optlen, | |
452 | optcode, &lease->ia)); | |
453 | ||
454 | break; | |
455 | ||
456 | case DHCP6_OPTION_SERVERID: | |
457 | assert_se(!found_serverid); | |
458 | found_serverid = true; | |
459 | ||
460 | assert_se(optlen == 14); | |
461 | assert_se(!memcmp(&msg_advertise[179], optval, optlen)); | |
462 | ||
d63be95a PF |
463 | break; |
464 | ||
465 | case DHCP6_OPTION_ELAPSED_TIME: | |
466 | assert_se(!found_elapsed_time); | |
467 | found_elapsed_time = true; | |
468 | ||
469 | assert_se(optlen == 2); | |
470 | ||
5e256ea7 PF |
471 | break; |
472 | } | |
473 | } | |
474 | ||
475 | assert_se(r == -ENOMSG); | |
d63be95a PF |
476 | assert_se(found_clientid && found_iana && found_serverid && |
477 | found_elapsed_time); | |
5e256ea7 | 478 | |
e7504d95 PF |
479 | sd_dhcp6_lease_reset_address_iter(lease); |
480 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, | |
481 | <_valid) >= 0); | |
5e256ea7 PF |
482 | assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); |
483 | assert_se(lt_pref == 150); | |
484 | assert_se(lt_valid == 180); | |
485 | ||
e7504d95 PF |
486 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, |
487 | <_valid) == -ENOMSG); | |
5e256ea7 | 488 | |
5e256ea7 PF |
489 | return 0; |
490 | } | |
491 | ||
52efd56a | 492 | static int test_client_send_advertise(DHCP6Message *solicit) { |
5e256ea7 PF |
493 | DHCP6Message advertise; |
494 | ||
495 | advertise.transaction_id = solicit->transaction_id; | |
496 | advertise.type = DHCP6_ADVERTISE; | |
497 | ||
498 | memcpy(msg_advertise, &advertise.transaction_id, 4); | |
499 | ||
500 | memcpy(&msg_advertise[8], test_duid, sizeof(test_duid)); | |
501 | ||
502 | memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid)); | |
503 | ||
504 | assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise)) | |
505 | == sizeof(msg_advertise)); | |
506 | ||
507 | return 0; | |
508 | } | |
509 | ||
510 | static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, | |
511 | size_t len) { | |
2ea8857e PF |
512 | uint8_t *optval; |
513 | uint16_t optcode; | |
514 | size_t optlen; | |
d63be95a PF |
515 | bool found_clientid = false, found_iana = false, |
516 | found_elapsed_time = false; | |
2ea8857e PF |
517 | int r; |
518 | ||
519 | assert_se(solicit->type == DHCP6_SOLICIT); | |
520 | ||
521 | while ((r = dhcp6_option_parse(&option, &len, | |
522 | &optcode, &optlen, &optval)) >= 0) { | |
523 | switch(optcode) { | |
524 | case DHCP6_OPTION_CLIENTID: | |
525 | assert_se(!found_clientid); | |
526 | found_clientid = true; | |
527 | ||
5e256ea7 PF |
528 | assert_se(optlen == sizeof(test_duid)); |
529 | memcpy(&test_duid, optval, sizeof(test_duid)); | |
2ea8857e PF |
530 | |
531 | break; | |
532 | ||
533 | case DHCP6_OPTION_IA_NA: | |
534 | assert_se(!found_iana); | |
535 | found_iana = true; | |
536 | ||
537 | assert_se(optlen == 12); | |
538 | ||
5e256ea7 PF |
539 | memcpy(&test_iaid, optval, sizeof(test_iaid)); |
540 | ||
d63be95a PF |
541 | break; |
542 | ||
543 | case DHCP6_OPTION_ELAPSED_TIME: | |
544 | assert_se(!found_elapsed_time); | |
545 | found_elapsed_time = true; | |
546 | ||
547 | assert_se(optlen == 2); | |
548 | ||
2ea8857e PF |
549 | break; |
550 | } | |
551 | } | |
552 | ||
553 | assert_se(r == -ENOMSG); | |
d63be95a | 554 | assert_se(found_clientid && found_iana && found_elapsed_time); |
2ea8857e | 555 | |
2ea8857e PF |
556 | return 0; |
557 | } | |
558 | ||
c4e8cedd PF |
559 | static void test_client_information_cb(sd_dhcp6_client *client, int event, |
560 | void *userdata) { | |
561 | sd_event *e = userdata; | |
bc152ff8 PF |
562 | sd_dhcp6_lease *lease; |
563 | struct in6_addr *addrs; | |
564 | char **domains; | |
c4e8cedd PF |
565 | |
566 | assert_se(e); | |
10c9ce61 | 567 | assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST); |
c4e8cedd | 568 | |
bc152ff8 PF |
569 | assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); |
570 | ||
571 | assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1); | |
572 | assert_se(!strcmp("lab.intra", domains[0])); | |
573 | assert_se(domains[1] == NULL); | |
574 | ||
575 | assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1); | |
576 | assert_se(!memcmp(addrs, &msg_advertise[124], 16)); | |
577 | ||
578 | assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); | |
579 | assert_se(!memcmp(addrs, &msg_advertise[159], 16)); | |
580 | ||
c4e8cedd PF |
581 | if (verbose) |
582 | printf(" got DHCPv6 event %d\n", event); | |
583 | ||
44598572 PF |
584 | assert_se(sd_dhcp6_client_set_information_request(client, false) == -EBUSY); |
585 | assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0); | |
586 | assert_se(sd_dhcp6_client_stop(client) >= 0); | |
c4e8cedd | 587 | assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0); |
44598572 | 588 | |
c4e8cedd PF |
589 | assert_se(sd_dhcp6_client_set_callback(client, |
590 | test_client_solicit_cb, e) >= 0); | |
591 | ||
592 | assert_se(sd_dhcp6_client_start(client) >= 0); | |
593 | } | |
594 | ||
595 | static int test_client_verify_information_request(DHCP6Message *information_request, | |
596 | uint8_t *option, size_t len) { | |
597 | ||
598 | _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; | |
599 | uint8_t *optval; | |
600 | uint16_t optcode; | |
601 | size_t optlen; | |
602 | bool found_clientid = false, found_elapsed_time = false; | |
603 | int r; | |
604 | struct in6_addr addr; | |
605 | uint32_t lt_pref, lt_valid; | |
606 | ||
607 | assert_se(information_request->type == DHCP6_INFORMATION_REQUEST); | |
608 | ||
609 | assert_se(dhcp6_lease_new(&lease) >= 0); | |
610 | ||
611 | while ((r = dhcp6_option_parse(&option, &len, | |
612 | &optcode, &optlen, &optval)) >= 0) { | |
613 | switch(optcode) { | |
614 | case DHCP6_OPTION_CLIENTID: | |
615 | assert_se(!found_clientid); | |
616 | found_clientid = true; | |
617 | ||
618 | assert_se(optlen == sizeof(test_duid)); | |
619 | memcpy(&test_duid, optval, sizeof(test_duid)); | |
620 | ||
621 | break; | |
622 | ||
623 | case DHCP6_OPTION_IA_NA: | |
624 | assert_not_reached("IA TA option must not be present"); | |
625 | ||
626 | break; | |
627 | ||
628 | case DHCP6_OPTION_SERVERID: | |
629 | assert_not_reached("Server ID option must not be present"); | |
630 | ||
631 | break; | |
632 | ||
633 | case DHCP6_OPTION_ELAPSED_TIME: | |
634 | assert_se(!found_elapsed_time); | |
635 | found_elapsed_time = true; | |
636 | ||
637 | assert_se(optlen == 2); | |
638 | ||
639 | break; | |
640 | } | |
641 | } | |
642 | ||
643 | assert_se(r == -ENOMSG); | |
644 | assert_se(found_clientid && found_elapsed_time); | |
645 | ||
e7504d95 | 646 | sd_dhcp6_lease_reset_address_iter(lease); |
c4e8cedd | 647 | |
e7504d95 PF |
648 | assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, |
649 | <_valid) == -ENOMSG); | |
c4e8cedd PF |
650 | |
651 | return 0; | |
652 | } | |
653 | ||
2ea8857e PF |
654 | int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, |
655 | const void *packet, size_t len) { | |
656 | struct in6_addr mcast = | |
657 | IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT; | |
658 | DHCP6Message *message; | |
659 | uint8_t *option; | |
660 | ||
661 | assert_se(s == test_dhcp_fd[0]); | |
662 | assert_se(server_address); | |
663 | assert_se(packet); | |
664 | assert_se(len > sizeof(DHCP6Message) + 4); | |
665 | ||
666 | assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast)); | |
667 | ||
668 | message = (DHCP6Message *)packet; | |
669 | option = (uint8_t *)(message + 1); | |
670 | len -= sizeof(DHCP6Message); | |
671 | ||
672 | assert_se(message->transaction_id & 0x00ffffff); | |
673 | ||
5e256ea7 | 674 | if (test_client_message_num == 0) { |
c4e8cedd PF |
675 | test_client_verify_information_request(message, option, len); |
676 | test_client_send_reply(message); | |
677 | test_client_message_num++; | |
678 | } else if (test_client_message_num == 1) { | |
5e256ea7 PF |
679 | test_client_verify_solicit(message, option, len); |
680 | test_client_send_advertise(message); | |
681 | test_client_message_num++; | |
c4e8cedd | 682 | } else if (test_client_message_num == 2) { |
5e256ea7 PF |
683 | test_client_verify_request(message, option, len); |
684 | test_client_send_reply(message); | |
685 | test_client_message_num++; | |
686 | } | |
2ea8857e PF |
687 | |
688 | return len; | |
689 | } | |
690 | ||
c4e8cedd PF |
691 | int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { |
692 | assert_se(index == test_index); | |
da6fe470 | 693 | |
c4e8cedd PF |
694 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0) |
695 | return -errno; | |
2ea8857e | 696 | |
c4e8cedd | 697 | return test_dhcp_fd[0]; |
2ea8857e PF |
698 | } |
699 | ||
700 | static int test_client_solicit(sd_event *e) { | |
701 | sd_dhcp6_client *client; | |
fa94c34b | 702 | usec_t time_now = now(clock_boottime_or_monotonic()); |
04c01369 | 703 | int val = true; |
2ea8857e PF |
704 | |
705 | if (verbose) | |
706 | printf("* %s\n", __FUNCTION__); | |
707 | ||
708 | assert_se(sd_dhcp6_client_new(&client) >= 0); | |
709 | assert_se(client); | |
710 | ||
711 | assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); | |
712 | ||
713 | assert_se(sd_dhcp6_client_set_index(client, test_index) == 0); | |
76253e73 DW |
714 | assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr, |
715 | sizeof (mac_addr), | |
716 | ARPHRD_ETHER) >= 0); | |
2ea8857e | 717 | |
c4e8cedd PF |
718 | assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0); |
719 | assert_se(val == false); | |
720 | assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0); | |
721 | assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0); | |
722 | assert_se(val == true); | |
723 | ||
2ea8857e | 724 | assert_se(sd_dhcp6_client_set_callback(client, |
c4e8cedd | 725 | test_client_information_cb, e) >= 0); |
2ea8857e | 726 | |
fa94c34b | 727 | assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(), |
2ea8857e PF |
728 | time_now + 2 * USEC_PER_SEC, 0, |
729 | test_hangcheck, NULL) >= 0); | |
730 | ||
2ea8857e PF |
731 | assert_se(sd_dhcp6_client_start(client) >= 0); |
732 | ||
733 | sd_event_loop(e); | |
734 | ||
735 | hangcheck = sd_event_source_unref(hangcheck); | |
736 | ||
737 | assert_se(!sd_dhcp6_client_unref(client)); | |
738 | ||
739 | test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]); | |
740 | ||
741 | return 0; | |
742 | } | |
743 | ||
813e3a6f PF |
744 | int main(int argc, char *argv[]) { |
745 | _cleanup_event_unref_ sd_event *e; | |
746 | ||
747 | assert_se(sd_event_new(&e) >= 0); | |
748 | ||
749 | log_set_max_level(LOG_DEBUG); | |
750 | log_parse_environment(); | |
751 | log_open(); | |
752 | ||
753 | test_client_basic(e); | |
f12ed3bf | 754 | test_option(e); |
859cca44 | 755 | test_advertise_option(e); |
2ea8857e | 756 | test_client_solicit(e); |
f12ed3bf | 757 | |
813e3a6f PF |
758 | return 0; |
759 | } |