1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 Intel Corporation. All rights reserved.
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.
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.
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/>.
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <net/ethernet.h>
29 #include "socket-util.h"
32 #include "event-util.h"
35 #include "sd-dhcp6-client.h"
36 #include "dhcp6-protocol.h"
37 #include "dhcp6-internal.h"
38 #include "dhcp6-lease-internal.h"
40 static struct ether_addr mac_addr = {
41 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
44 static bool verbose = false;
46 static sd_event_source *hangcheck;
47 static int test_dhcp_fd[2];
48 static int test_index = 42;
49 static int test_client_message_num;
50 static be32_t test_iaid = 0;
51 static uint8_t test_duid[14] = { };
53 static int test_client_basic(sd_event *e) {
54 sd_dhcp6_client *client;
57 printf("* %s\n", __FUNCTION__);
59 assert_se(sd_dhcp6_client_new(&client) >= 0);
62 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
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);
69 assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
71 assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL);
72 assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
73 assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST);
74 assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == 0);
75 assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
76 assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
78 assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
80 assert_se(sd_dhcp6_client_detach_event(client) >= 0);
81 assert_se(!sd_dhcp6_client_unref(client));
86 static int test_option(sd_event *e) {
89 0x00, DHCP6_OPTION_ORO, 0x00, 0x07,
90 'A', 'B', 'C', 'D', 'E', 'F', 'G',
91 0x00, DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
92 '1', '2', '3', '4', '5', '6', '7', '8', '9',
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 uint8_t *optval, *buf, *out;
105 size_t zero = 0, pos = 3;
106 size_t buflen = sizeof(packet), outlen = sizeof(result);
109 printf("* %s\n", __FUNCTION__);
111 assert_se(buflen == outlen);
113 assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
114 &optval) == -ENOMSG);
121 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
124 assert_se(buf == &packet[pos]);
125 assert_se(optcode == DHCP6_OPTION_ORO);
126 assert_se(optlen == 7);
127 assert_se(buflen + pos == sizeof(packet));
129 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
131 assert_se(out == &result[pos]);
132 assert_se(*out == 0x00);
134 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
137 assert_se(buf == &packet[pos]);
138 assert_se(optcode == DHCP6_OPTION_VENDOR_CLASS);
139 assert_se(optlen == 9);
140 assert_se(buflen + pos == sizeof(packet));
142 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
144 assert_se(out == &result[pos]);
145 assert_se(*out == 'B');
147 assert_se(memcmp(packet, result, sizeof(packet)) == 0);
152 static uint8_t msg_advertise[198] = {
153 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
154 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
155 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
156 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
157 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
158 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
159 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
160 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
161 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
162 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
163 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
164 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
165 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
166 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
167 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
168 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
169 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
171 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
172 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
173 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
175 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
176 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
177 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
180 static uint8_t msg_reply[173] = {
181 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
182 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
183 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
184 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
185 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
186 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
187 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
188 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
189 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
190 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
191 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
192 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
193 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
194 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
195 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
196 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
197 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
199 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
200 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
201 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x01
205 static int test_advertise_option(sd_event *e) {
206 _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
207 DHCP6Message *advertise = (DHCP6Message *)msg_advertise;
208 uint8_t *optval, *opt = &msg_advertise[sizeof(DHCP6Message)];
210 size_t optlen, len = sizeof(msg_advertise);
212 uint8_t preference = 255;
213 struct in6_addr addr;
214 uint32_t lt_pref, lt_valid;
216 bool opt_clientid = false;
219 printf("* %s\n", __FUNCTION__);
221 assert_se(dhcp6_lease_new(&lease) >= 0);
223 assert_se(advertise->type == DHCP6_ADVERTISE);
224 assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) ==
227 while ((r = dhcp6_option_parse(&opt, &len, &optcode, &optlen,
231 case DHCP6_OPTION_CLIENTID:
232 assert_se(optlen == 14);
237 case DHCP6_OPTION_IA_NA:
238 assert_se(optlen == 94);
239 assert_se(!memcmp(optval, &msg_advertise[26], optlen));
241 val = htobe32(0x0ecfa37d);
242 assert_se(!memcmp(optval, &val, sizeof(val)));
245 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
248 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
250 assert_se(dhcp6_option_parse_ia(&optval, &optlen,
256 case DHCP6_OPTION_SERVERID:
257 assert_se(optlen == 14);
258 assert_se(!memcmp(optval, &msg_advertise[179], optlen));
260 assert_se(dhcp6_lease_set_serverid(lease, optval,
264 case DHCP6_OPTION_PREFERENCE:
265 assert_se(optlen == 1);
268 assert_se(dhcp6_lease_set_preference(lease,
278 assert_se(r == -ENOMSG);
280 assert_se(opt_clientid);
282 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
284 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
285 assert_se(lt_pref == 150);
286 assert_se(lt_valid == 180);
287 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
288 <_valid) == -ENOMSG);
290 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
292 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
293 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
294 <_valid) == -ENOMSG);
295 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
296 <_valid) == -ENOMSG);
297 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
299 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
300 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
301 <_valid) == -ENOMSG);
303 assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0);
304 assert_se(len == 14);
305 assert_se(!memcmp(opt, &msg_advertise[179], len));
307 assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0);
308 assert_se(preference == 0);
313 static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
314 assert_not_reached("Test case should have completed in 2 seconds");
319 int detect_vm(const char **id) {
323 int detect_container(const char **id) {
327 int detect_virtualization(const char **id) {
331 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
332 assert_se(index == test_index);
334 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
337 return test_dhcp_fd[0];
340 static int test_client_send_reply(DHCP6Message *request) {
343 reply.transaction_id = request->transaction_id;
344 reply.type = DHCP6_REPLY;
346 memcpy(msg_reply, &reply.transaction_id, 4);
348 memcpy(&msg_reply[26], test_duid, sizeof(test_duid));
350 memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid));
352 assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply))
353 == sizeof(msg_reply));
358 static int test_client_verify_request(DHCP6Message *request, uint8_t *option,
360 _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
364 bool found_clientid = false, found_iana = false, found_serverid = false;
366 struct in6_addr addr;
368 uint32_t lt_pref, lt_valid;
370 assert_se(request->type == DHCP6_REQUEST);
372 assert_se(dhcp6_lease_new(&lease) >= 0);
374 while ((r = dhcp6_option_parse(&option, &len,
375 &optcode, &optlen, &optval)) >= 0) {
377 case DHCP6_OPTION_CLIENTID:
378 assert_se(!found_clientid);
379 found_clientid = true;
381 assert_se(!memcmp(optval, &test_duid,
386 case DHCP6_OPTION_IA_NA:
387 assert_se(!found_iana);
391 assert_se(optlen == 40);
392 assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
395 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
398 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
400 assert_se(!dhcp6_option_parse_ia(&optval, &optlen,
401 optcode, &lease->ia));
405 case DHCP6_OPTION_SERVERID:
406 assert_se(!found_serverid);
407 found_serverid = true;
409 assert_se(optlen == 14);
410 assert_se(!memcmp(&msg_advertise[179], optval, optlen));
416 assert_se(r == -ENOMSG);
417 assert_se(found_clientid && found_iana && found_serverid);
419 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
421 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
422 assert_se(lt_pref == 150);
423 assert_se(lt_valid == 180);
425 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
426 <_valid) == -ENOMSG);
431 static int test_client_send_advertise(DHCP6Message *solicit)
433 DHCP6Message advertise;
435 advertise.transaction_id = solicit->transaction_id;
436 advertise.type = DHCP6_ADVERTISE;
438 memcpy(msg_advertise, &advertise.transaction_id, 4);
440 memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
442 memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
444 assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
445 == sizeof(msg_advertise));
450 static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option,
455 bool found_clientid = false, found_iana = false;
458 assert_se(solicit->type == DHCP6_SOLICIT);
460 while ((r = dhcp6_option_parse(&option, &len,
461 &optcode, &optlen, &optval)) >= 0) {
463 case DHCP6_OPTION_CLIENTID:
464 assert_se(!found_clientid);
465 found_clientid = true;
467 assert_se(optlen == sizeof(test_duid));
468 memcpy(&test_duid, optval, sizeof(test_duid));
472 case DHCP6_OPTION_IA_NA:
473 assert_se(!found_iana);
476 assert_se(optlen == 12);
478 memcpy(&test_iaid, optval, sizeof(test_iaid));
484 assert_se(r == -ENOMSG);
485 assert_se(found_clientid && found_iana);
490 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
491 const void *packet, size_t len) {
492 struct in6_addr mcast =
493 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
494 DHCP6Message *message;
497 assert_se(s == test_dhcp_fd[0]);
498 assert_se(server_address);
500 assert_se(len > sizeof(DHCP6Message) + 4);
502 assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
504 message = (DHCP6Message *)packet;
505 option = (uint8_t *)(message + 1);
506 len -= sizeof(DHCP6Message);
508 assert_se(message->transaction_id & 0x00ffffff);
510 if (test_client_message_num == 0) {
511 test_client_verify_solicit(message, option, len);
512 test_client_send_advertise(message);
513 test_client_message_num++;
514 } else if (test_client_message_num == 1) {
515 test_client_verify_request(message, option, len);
516 test_client_send_reply(message);
517 test_client_message_num++;
523 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
525 sd_event *e = userdata;
528 assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
530 assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
533 printf(" got DHCPv6 event %d\n", event);
538 static int test_client_solicit(sd_event *e) {
539 sd_dhcp6_client *client;
540 usec_t time_now = now(clock_boottime_or_monotonic());
543 printf("* %s\n", __FUNCTION__);
545 assert_se(sd_dhcp6_client_new(&client) >= 0);
548 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
550 assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
551 assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
553 assert_se(sd_dhcp6_client_set_callback(client,
554 test_client_solicit_cb, e) >= 0);
556 assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
557 time_now + 2 * USEC_PER_SEC, 0,
558 test_hangcheck, NULL) >= 0);
560 assert_se(sd_dhcp6_client_start(client) >= 0);
564 hangcheck = sd_event_source_unref(hangcheck);
566 assert_se(!sd_dhcp6_client_unref(client));
568 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
573 int main(int argc, char *argv[]) {
574 _cleanup_event_unref_ sd_event *e;
576 assert_se(sd_event_new(&e) >= 0);
578 log_set_max_level(LOG_DEBUG);
579 log_parse_environment();
582 test_client_basic(e);
584 test_advertise_option(e);
585 test_client_solicit(e);
587 assert_se(!sd_event_unref(e));