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