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-protocol.h"
36 #include "dhcp-internal.h"
37 #include "sd-dhcp-client.h"
39 static struct ether_addr mac_addr = {
40 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
43 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
45 static bool verbose = false;
46 static int test_fd[2];
47 static test_callback_recv_t callback_recv;
49 static sd_event_source *test_hangcheck;
51 static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
54 assert_not_reached("Test case should have completed in 2 seconds");
59 static void test_request_basic(sd_event *e)
63 sd_dhcp_client *client;
66 printf("* %s\n", __FUNCTION__);
68 r = sd_dhcp_client_new(&client);
73 r = sd_dhcp_client_attach_event(client, e, 0);
76 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
77 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
78 assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
80 assert_se(sd_dhcp_client_set_index(client, 15) == 0);
81 assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
82 assert_se(sd_dhcp_client_set_index(client, -1) == -EINVAL);
83 assert_se(sd_dhcp_client_set_index(client, 0) == -EINVAL);
84 assert_se(sd_dhcp_client_set_index(client, 1) == 0);
86 assert_se(sd_dhcp_client_set_request_option(client,
87 DHCP_OPTION_SUBNET_MASK) == -EEXIST);
88 assert_se(sd_dhcp_client_set_request_option(client,
89 DHCP_OPTION_ROUTER) == -EEXIST);
90 assert_se(sd_dhcp_client_set_request_option(client,
91 DHCP_OPTION_HOST_NAME) == -EEXIST);
92 assert_se(sd_dhcp_client_set_request_option(client,
93 DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
94 assert_se(sd_dhcp_client_set_request_option(client,
95 DHCP_OPTION_DOMAIN_NAME_SERVER)
97 assert_se(sd_dhcp_client_set_request_option(client,
98 DHCP_OPTION_NTP_SERVER) == -EEXIST);
100 assert_se(sd_dhcp_client_set_request_option(client,
101 DHCP_OPTION_PAD) == -EINVAL);
102 assert_se(sd_dhcp_client_set_request_option(client,
103 DHCP_OPTION_END) == -EINVAL);
104 assert_se(sd_dhcp_client_set_request_option(client,
105 DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
106 assert_se(sd_dhcp_client_set_request_option(client,
107 DHCP_OPTION_OVERLOAD) == -EINVAL);
108 assert_se(sd_dhcp_client_set_request_option(client,
109 DHCP_OPTION_PARAMETER_REQUEST_LIST)
112 assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
113 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
114 assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
115 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
117 sd_dhcp_client_unref(client);
120 static void test_checksum(void)
123 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
124 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0xff, 0xff, 0xff, 0xff
129 printf("* %s\n", __FUNCTION__);
131 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
134 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
138 case DHCP_OPTION_CLIENT_IDENTIFIER:
140 assert_se(option[0] == 0x01);
141 assert_se(memcmp(&option[1], &mac_addr, ETH_ALEN) == 0);
151 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
152 const void *packet, size_t len)
155 _cleanup_free_ DHCPPacket *discover;
156 uint16_t ip_check, udp_check;
161 size = sizeof(DHCPPacket);
162 assert_se(len > size);
164 discover = memdup(packet, len);
166 assert_se(discover->ip.ttl == IPDEFTTL);
167 assert_se(discover->ip.protocol == IPPROTO_UDP);
168 assert_se(discover->ip.saddr == INADDR_ANY);
169 assert_se(discover->ip.daddr == INADDR_BROADCAST);
170 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
171 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
173 ip_check = discover->ip.check;
175 discover->ip.ttl = 0;
176 discover->ip.check = discover->udp.len;
178 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
179 assert_se(udp_check == 0xffff);
181 discover->ip.ttl = IPDEFTTL;
182 discover->ip.check = ip_check;
184 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
185 assert_se(ip_check == 0xffff);
187 assert_se(discover->dhcp.xid);
188 assert_se(memcmp(discover->dhcp.chaddr,
189 &mac_addr.ether_addr_octet, 6) == 0);
191 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
193 assert_se(callback_recv);
194 callback_recv(size, &discover->dhcp);
199 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
200 uint32_t id, const uint8_t *addr,
201 size_t addr_len, uint16_t arp_type)
203 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
209 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
214 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
215 const void *packet, size_t len)
220 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
224 res = dhcp_option_parse(dhcp, size, check_options, NULL);
225 assert_se(res == DHCP_DISCOVER);
228 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
233 static void test_discover_message(sd_event *e)
235 sd_dhcp_client *client;
239 printf("* %s\n", __FUNCTION__);
241 r = sd_dhcp_client_new(&client);
245 r = sd_dhcp_client_attach_event(client, e, 0);
248 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
249 assert_se(sd_dhcp_client_set_mac(client,
250 (const uint8_t *) &mac_addr,
254 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
256 callback_recv = test_discover_message_verify;
258 res = sd_dhcp_client_start(client);
260 assert_se(res == 0 || res == -EINPROGRESS);
262 sd_event_run(e, (uint64_t) -1);
264 sd_dhcp_client_stop(client);
265 sd_dhcp_client_unref(client);
267 test_fd[1] = safe_close(test_fd[1]);
269 callback_recv = NULL;
272 static uint8_t test_addr_acq_offer[] = {
273 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
274 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
275 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
276 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
277 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
279 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
307 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
308 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
309 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
310 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
311 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
312 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 static uint8_t test_addr_acq_ack[] = {
317 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
318 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
319 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
320 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
323 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
351 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
352 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
353 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
354 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
355 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
356 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
362 sd_event *e = userdata;
363 sd_dhcp_lease *lease;
367 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
369 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
372 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
373 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
374 sizeof(addr.s_addr)) == 0);
376 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
377 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
378 sizeof(addr.s_addr)) == 0);
380 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
381 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
382 sizeof(addr.s_addr)) == 0);
385 printf(" DHCP address acquired\n");
387 sd_dhcp_lease_unref(lease);
391 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
392 uint16_t udp_check = 0;
393 uint8_t *msg_bytes = (uint8_t *)request;
396 res = dhcp_option_parse(request, size, check_options, NULL);
397 assert_se(res == DHCP_REQUEST);
398 assert_se(xid == request->xid);
400 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
403 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
405 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
406 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
407 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
410 callback_recv = NULL;
412 res = write(test_fd[1], test_addr_acq_ack,
413 sizeof(test_addr_acq_ack));
414 assert_se(res == sizeof(test_addr_acq_ack));
417 printf(" send DHCP Ack\n");
422 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
423 uint16_t udp_check = 0;
424 uint8_t *msg_bytes = (uint8_t *)discover;
427 res = dhcp_option_parse(discover, size, check_options, NULL);
428 assert_se(res == DHCP_DISCOVER);
430 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
435 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
437 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
438 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
439 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
442 callback_recv = test_addr_acq_recv_request;
444 res = write(test_fd[1], test_addr_acq_offer,
445 sizeof(test_addr_acq_offer));
446 assert_se(res == sizeof(test_addr_acq_offer));
449 printf(" sent DHCP Offer\n");
454 static void test_addr_acq(sd_event *e) {
455 usec_t time_now = now(clock_boottime_or_monotonic());
456 sd_dhcp_client *client;
460 printf("* %s\n", __FUNCTION__);
462 r = sd_dhcp_client_new(&client);
466 r = sd_dhcp_client_attach_event(client, e, 0);
469 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
470 assert_se(sd_dhcp_client_set_mac(client,
471 (const uint8_t *) &mac_addr,
475 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
478 callback_recv = test_addr_acq_recv_discover;
480 assert_se(sd_event_add_time(e, &test_hangcheck,
481 clock_boottime_or_monotonic(),
482 time_now + 2 * USEC_PER_SEC, 0,
483 test_dhcp_hangcheck, NULL) >= 0);
485 res = sd_dhcp_client_start(client);
486 assert_se(res == 0 || res == -EINPROGRESS);
488 assert_se(sd_event_loop(e) >= 0);
490 test_hangcheck = sd_event_source_unref(test_hangcheck);
492 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
493 assert_se(sd_dhcp_client_stop(client) >= 0);
494 sd_dhcp_client_unref(client);
496 test_fd[1] = safe_close(test_fd[1]);
498 callback_recv = NULL;
502 int main(int argc, char *argv[]) {
503 _cleanup_event_unref_ sd_event *e;
505 log_set_max_level(LOG_DEBUG);
506 log_parse_environment();
509 assert_se(sd_event_new(&e) >= 0);
511 test_request_basic(e);
514 test_discover_message(e);