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] = { };
52 static sd_event *e_solicit;
54 static int test_client_basic(sd_event *e) {
55 sd_dhcp6_client *client;
58 printf("* %s\n", __FUNCTION__);
60 assert_se(sd_dhcp6_client_new(&client) >= 0);
63 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
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);
70 assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
72 assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
74 assert_se(sd_dhcp6_client_detach_event(client) >= 0);
75 assert_se(!sd_dhcp6_client_unref(client));
80 static int test_option(sd_event *e) {
83 0x00, DHCP6_OPTION_ORO, 0x00, 0x07,
84 'A', 'B', 'C', 'D', 'E', 'F', 'G',
85 0x00, DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
86 '1', '2', '3', '4', '5', '6', '7', '8', '9',
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 uint8_t *optval, *buf, *out;
99 size_t zero = 0, pos = 3;
100 size_t buflen = sizeof(packet), outlen = sizeof(result);
103 printf("* %s\n", __FUNCTION__);
105 assert_se(buflen == outlen);
107 assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
108 &optval) == -ENOMSG);
115 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
118 assert_se(buf == &packet[pos]);
119 assert_se(optcode == DHCP6_OPTION_ORO);
120 assert_se(optlen == 7);
121 assert_se(buflen + pos == sizeof(packet));
123 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
125 assert_se(out == &result[pos]);
126 assert_se(*out == 0x00);
128 assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
131 assert_se(buf == &packet[pos]);
132 assert_se(optcode == DHCP6_OPTION_VENDOR_CLASS);
133 assert_se(optlen == 9);
134 assert_se(buflen + pos == sizeof(packet));
136 assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
138 assert_se(out == &result[pos]);
139 assert_se(*out == 'B');
141 assert_se(memcmp(packet, result, sizeof(packet)) == 0);
146 static uint8_t msg_advertise[198] = {
147 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
148 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
149 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
150 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
151 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
152 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
153 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
154 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
155 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
156 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
157 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
158 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
159 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
160 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
161 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
162 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
163 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
165 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
166 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
167 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
169 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
170 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
171 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
174 static int test_advertise_option(sd_event *e) {
175 _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
176 DHCP6Message *advertise = (DHCP6Message *)msg_advertise;
177 uint8_t *optval, *opt = &msg_advertise[sizeof(DHCP6Message)];
179 size_t optlen, len = sizeof(msg_advertise);
181 uint8_t preference = 255;
182 struct in6_addr addr;
183 uint32_t lt_pref, lt_valid;
185 bool opt_clientid = false;
188 printf("* %s\n", __FUNCTION__);
190 assert_se(dhcp6_lease_new(&lease) >= 0);
192 assert_se(advertise->type == DHCP6_ADVERTISE);
193 assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) ==
196 while ((r = dhcp6_option_parse(&opt, &len, &optcode, &optlen,
200 case DHCP6_OPTION_CLIENTID:
201 assert_se(optlen == 14);
206 case DHCP6_OPTION_IA_NA:
207 assert_se(optlen == 94);
208 assert_se(!memcmp(optval, &msg_advertise[26], optlen));
210 val = htobe32(0x0ecfa37d);
211 assert_se(!memcmp(optval, &val, sizeof(val)));
214 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
217 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
219 assert_se(dhcp6_option_parse_ia(&optval, &optlen,
225 case DHCP6_OPTION_SERVERID:
226 assert_se(optlen == 14);
227 assert_se(!memcmp(optval, &msg_advertise[179], optlen));
229 assert_se(dhcp6_lease_set_serverid(lease, optval,
233 case DHCP6_OPTION_PREFERENCE:
234 assert_se(optlen == 1);
237 assert_se(dhcp6_lease_set_preference(lease,
247 assert_se(r == -ENOMSG);
249 assert_se(opt_clientid);
251 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
253 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
254 assert_se(lt_pref == 150);
255 assert_se(lt_valid == 180);
256 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
257 <_valid) == -ENOMSG);
259 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
261 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
262 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
263 <_valid) == -ENOMSG);
264 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
265 <_valid) == -ENOMSG);
266 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
268 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
269 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
270 <_valid) == -ENOMSG);
272 assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0);
273 assert_se(len == 14);
274 assert_se(!memcmp(opt, &msg_advertise[179], len));
276 assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0);
277 assert_se(preference == 0);
282 static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
283 assert_not_reached("Test case should have completed in 2 seconds");
288 int detect_vm(const char **id) {
292 int detect_container(const char **id) {
296 int detect_virtualization(const char **id) {
300 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
301 assert_se(index == test_index);
303 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
306 return test_dhcp_fd[0];
309 static int test_client_send_reply(DHCP6Message *request) {
313 static int test_client_verify_request(DHCP6Message *request, uint8_t *option,
315 _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
319 bool found_clientid = false, found_iana = false, found_serverid = false;
321 struct in6_addr addr;
323 uint32_t lt_pref, lt_valid;
325 assert_se(request->type == DHCP6_REQUEST);
327 assert_se(dhcp6_lease_new(&lease) >= 0);
329 while ((r = dhcp6_option_parse(&option, &len,
330 &optcode, &optlen, &optval)) >= 0) {
332 case DHCP6_OPTION_CLIENTID:
333 assert_se(!found_clientid);
334 found_clientid = true;
336 assert_se(!memcmp(optval, &test_duid,
341 case DHCP6_OPTION_IA_NA:
342 assert_se(!found_iana);
346 assert_se(optlen == 40);
347 assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
350 assert_se(!memcmp(optval + 4, &val, sizeof(val)));
353 assert_se(!memcmp(optval + 8, &val, sizeof(val)));
355 assert_se(!dhcp6_option_parse_ia(&optval, &optlen,
356 optcode, &lease->ia));
360 case DHCP6_OPTION_SERVERID:
361 assert_se(!found_serverid);
362 found_serverid = true;
364 assert_se(optlen == 14);
365 assert_se(!memcmp(&msg_advertise[179], optval, optlen));
371 assert_se(r == -ENOMSG);
372 assert_se(found_clientid && found_iana && found_serverid);
374 assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref,
376 assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
377 assert_se(lt_pref == 150);
378 assert_se(lt_valid == 180);
380 assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, <_pref,
381 <_valid) == -ENOMSG);
383 sd_event_exit(e_solicit, 0);
388 static int test_client_send_advertise(DHCP6Message *solicit)
390 DHCP6Message advertise;
392 advertise.transaction_id = solicit->transaction_id;
393 advertise.type = DHCP6_ADVERTISE;
395 memcpy(msg_advertise, &advertise.transaction_id, 4);
397 memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
399 memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
401 assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
402 == sizeof(msg_advertise));
407 static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option,
412 bool found_clientid = false, found_iana = false;
415 assert_se(solicit->type == DHCP6_SOLICIT);
417 while ((r = dhcp6_option_parse(&option, &len,
418 &optcode, &optlen, &optval)) >= 0) {
420 case DHCP6_OPTION_CLIENTID:
421 assert_se(!found_clientid);
422 found_clientid = true;
424 assert_se(optlen == sizeof(test_duid));
425 memcpy(&test_duid, optval, sizeof(test_duid));
429 case DHCP6_OPTION_IA_NA:
430 assert_se(!found_iana);
433 assert_se(optlen == 12);
435 memcpy(&test_iaid, optval, sizeof(test_iaid));
441 assert_se(r == -ENOMSG);
442 assert_se(found_clientid && found_iana);
447 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
448 const void *packet, size_t len) {
449 struct in6_addr mcast =
450 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
451 DHCP6Message *message;
454 assert_se(s == test_dhcp_fd[0]);
455 assert_se(server_address);
457 assert_se(len > sizeof(DHCP6Message) + 4);
459 assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
461 message = (DHCP6Message *)packet;
462 option = (uint8_t *)(message + 1);
463 len -= sizeof(DHCP6Message);
465 assert_se(message->transaction_id & 0x00ffffff);
467 if (test_client_message_num == 0) {
468 test_client_verify_solicit(message, option, len);
469 test_client_send_advertise(message);
470 test_client_message_num++;
471 } else if (test_client_message_num == 1) {
472 test_client_verify_request(message, option, len);
473 test_client_send_reply(message);
474 test_client_message_num++;
480 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
482 sd_event *e = userdata;
487 printf(" got DHCPv6 event %d\n", event);
492 static int test_client_solicit(sd_event *e) {
493 sd_dhcp6_client *client;
494 usec_t time_now = now(CLOCK_MONOTONIC);
497 printf("* %s\n", __FUNCTION__);
499 assert_se(sd_dhcp6_client_new(&client) >= 0);
502 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
504 assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
505 assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
507 assert_se(sd_dhcp6_client_set_callback(client,
508 test_client_solicit_cb, e) >= 0);
510 assert_se(sd_event_add_time(e, &hangcheck, CLOCK_MONOTONIC,
511 time_now + 2 * USEC_PER_SEC, 0,
512 test_hangcheck, NULL) >= 0);
516 assert_se(sd_dhcp6_client_start(client) >= 0);
520 hangcheck = sd_event_source_unref(hangcheck);
522 assert_se(!sd_dhcp6_client_unref(client));
524 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
529 int main(int argc, char *argv[]) {
530 _cleanup_event_unref_ sd_event *e;
532 assert_se(sd_event_new(&e) >= 0);
534 log_set_max_level(LOG_DEBUG);
535 log_parse_environment();
538 test_client_basic(e);
540 test_advertise_option(e);
541 test_client_solicit(e);
543 assert_se(!sd_event_unref(e));