1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 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/>.
26 #include <sys/types.h>
27 #include <sys/socket.h>
31 #include "socket-util.h"
33 #include "event-util.h"
35 #include "dhcp-identifier.h"
36 #include "dhcp-protocol.h"
37 #include "dhcp-internal.h"
38 #include "sd-dhcp-client.h"
40 static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
42 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
44 static bool verbose = true;
45 static int test_fd[2];
46 static test_callback_recv_t callback_recv;
48 static sd_event_source *test_hangcheck;
50 static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
53 assert_not_reached("Test case should have completed in 2 seconds");
58 static void test_request_basic(sd_event *e)
62 sd_dhcp_client *client;
65 printf("* %s\n", __FUNCTION__);
67 r = sd_dhcp_client_new(&client);
72 r = sd_dhcp_client_attach_event(client, e, 0);
75 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
76 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
77 assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
79 assert_se(sd_dhcp_client_set_index(client, 15) == 0);
80 assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
81 assert_se(sd_dhcp_client_set_index(client, -1) == -EINVAL);
82 assert_se(sd_dhcp_client_set_index(client, 0) == -EINVAL);
83 assert_se(sd_dhcp_client_set_index(client, 1) == 0);
85 assert_se(sd_dhcp_client_set_request_option(client,
86 DHCP_OPTION_SUBNET_MASK) == -EEXIST);
87 assert_se(sd_dhcp_client_set_request_option(client,
88 DHCP_OPTION_ROUTER) == -EEXIST);
89 assert_se(sd_dhcp_client_set_request_option(client,
90 DHCP_OPTION_HOST_NAME) == -EEXIST);
91 assert_se(sd_dhcp_client_set_request_option(client,
92 DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
93 assert_se(sd_dhcp_client_set_request_option(client,
94 DHCP_OPTION_DOMAIN_NAME_SERVER)
96 assert_se(sd_dhcp_client_set_request_option(client,
97 DHCP_OPTION_NTP_SERVER) == -EEXIST);
99 assert_se(sd_dhcp_client_set_request_option(client,
100 DHCP_OPTION_PAD) == -EINVAL);
101 assert_se(sd_dhcp_client_set_request_option(client,
102 DHCP_OPTION_END) == -EINVAL);
103 assert_se(sd_dhcp_client_set_request_option(client,
104 DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
105 assert_se(sd_dhcp_client_set_request_option(client,
106 DHCP_OPTION_OVERLOAD) == -EINVAL);
107 assert_se(sd_dhcp_client_set_request_option(client,
108 DHCP_OPTION_PARAMETER_REQUEST_LIST)
111 assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
112 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
113 assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
114 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
116 sd_dhcp_client_unref(client);
119 static void test_checksum(void)
122 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
123 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0xff, 0xff, 0xff, 0xff
128 printf("* %s\n", __FUNCTION__);
130 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
133 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
137 case DHCP_OPTION_CLIENT_IDENTIFIER:
143 assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0);
144 assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, &iaid) >= 0);
146 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
147 assert_se(len == 19);
148 assert_se(option[0] == 0xff);
150 assert_se(memcmp(&option[1], &iaid, sizeof(iaid)) == 0);
151 assert_se(memcmp(&option[5], &duid, duid_len) == 0);
162 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
163 const void *packet, size_t len)
166 _cleanup_free_ DHCPPacket *discover;
167 uint16_t ip_check, udp_check;
172 size = sizeof(DHCPPacket);
173 assert_se(len > size);
175 discover = memdup(packet, len);
177 assert_se(discover->ip.ttl == IPDEFTTL);
178 assert_se(discover->ip.protocol == IPPROTO_UDP);
179 assert_se(discover->ip.saddr == INADDR_ANY);
180 assert_se(discover->ip.daddr == INADDR_BROADCAST);
181 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
182 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
184 ip_check = discover->ip.check;
186 discover->ip.ttl = 0;
187 discover->ip.check = discover->udp.len;
189 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
190 assert_se(udp_check == 0xffff);
192 discover->ip.ttl = IPDEFTTL;
193 discover->ip.check = ip_check;
195 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
196 assert_se(ip_check == 0xffff);
198 assert_se(discover->dhcp.xid);
199 assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
201 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
203 assert_se(callback_recv);
204 callback_recv(size, &discover->dhcp);
209 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
210 uint32_t id, const uint8_t *addr,
211 size_t addr_len, uint16_t arp_type)
213 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
219 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
223 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
230 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
231 const void *packet, size_t len)
236 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
240 res = dhcp_option_parse(dhcp, size, check_options, NULL);
241 assert_se(res == DHCP_DISCOVER);
244 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
249 static void test_discover_message(sd_event *e)
251 sd_dhcp_client *client;
255 printf("* %s\n", __FUNCTION__);
257 r = sd_dhcp_client_new(&client);
261 r = sd_dhcp_client_attach_event(client, e, 0);
264 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
265 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
267 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
269 callback_recv = test_discover_message_verify;
271 res = sd_dhcp_client_start(client);
273 assert_se(res == 0 || res == -EINPROGRESS);
275 sd_event_run(e, (uint64_t) -1);
277 sd_dhcp_client_stop(client);
278 sd_dhcp_client_unref(client);
280 test_fd[1] = safe_close(test_fd[1]);
282 callback_recv = NULL;
285 static uint8_t test_addr_acq_offer[] = {
286 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
287 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
288 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
289 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
290 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
292 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
320 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
321 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
322 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
323 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
324 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
325 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 static uint8_t test_addr_acq_ack[] = {
330 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
331 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
332 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
333 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
336 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
364 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
365 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
366 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
367 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
368 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
369 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
373 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
375 sd_event *e = userdata;
376 sd_dhcp_lease *lease;
380 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
382 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
385 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
386 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
387 sizeof(addr.s_addr)) == 0);
389 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
390 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
391 sizeof(addr.s_addr)) == 0);
393 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
394 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
395 sizeof(addr.s_addr)) == 0);
398 printf(" DHCP address acquired\n");
400 sd_dhcp_lease_unref(lease);
404 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
405 uint16_t udp_check = 0;
406 uint8_t *msg_bytes = (uint8_t *)request;
409 res = dhcp_option_parse(request, size, check_options, NULL);
410 assert_se(res == DHCP_REQUEST);
411 assert_se(xid == request->xid);
413 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
416 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
418 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
419 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
420 memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
422 callback_recv = NULL;
424 res = write(test_fd[1], test_addr_acq_ack,
425 sizeof(test_addr_acq_ack));
426 assert_se(res == sizeof(test_addr_acq_ack));
429 printf(" send DHCP Ack\n");
434 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
435 uint16_t udp_check = 0;
436 uint8_t *msg_bytes = (uint8_t *)discover;
439 res = dhcp_option_parse(discover, size, check_options, NULL);
440 assert_se(res == DHCP_DISCOVER);
442 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
447 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
449 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
450 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
451 memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
453 callback_recv = test_addr_acq_recv_request;
455 res = write(test_fd[1], test_addr_acq_offer,
456 sizeof(test_addr_acq_offer));
457 assert_se(res == sizeof(test_addr_acq_offer));
460 printf(" sent DHCP Offer\n");
465 static void test_addr_acq(sd_event *e) {
466 usec_t time_now = now(clock_boottime_or_monotonic());
467 sd_dhcp_client *client;
471 printf("* %s\n", __FUNCTION__);
473 r = sd_dhcp_client_new(&client);
477 r = sd_dhcp_client_attach_event(client, e, 0);
480 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
481 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
483 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
485 callback_recv = test_addr_acq_recv_discover;
487 assert_se(sd_event_add_time(e, &test_hangcheck,
488 clock_boottime_or_monotonic(),
489 time_now + 2 * USEC_PER_SEC, 0,
490 test_dhcp_hangcheck, NULL) >= 0);
492 res = sd_dhcp_client_start(client);
493 assert_se(res == 0 || res == -EINPROGRESS);
495 assert_se(sd_event_loop(e) >= 0);
497 test_hangcheck = sd_event_source_unref(test_hangcheck);
499 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
500 assert_se(sd_dhcp_client_stop(client) >= 0);
501 sd_dhcp_client_unref(client);
503 test_fd[1] = safe_close(test_fd[1]);
505 callback_recv = NULL;
509 int main(int argc, char *argv[]) {
510 _cleanup_event_unref_ sd_event *e;
512 log_set_max_level(LOG_DEBUG);
513 log_parse_environment();
516 assert_se(sd_event_new(&e) >= 0);
518 test_request_basic(e);
521 test_discover_message(e);
525 /* Make sure the async_close thread has finished.
526 * valgrind would report some of the phread_* structures
527 * as not cleaned up properly. */