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/>.
24 #include <sys/socket.h>
29 #include "event-util.h"
31 #include "dhcp-identifier.h"
32 #include "dhcp-protocol.h"
33 #include "dhcp-internal.h"
34 #include "sd-dhcp-client.h"
36 static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
38 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
40 static bool verbose = true;
41 static int test_fd[2];
42 static test_callback_recv_t callback_recv;
44 static sd_event_source *test_hangcheck;
46 static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
49 assert_not_reached("Test case should have completed in 2 seconds");
54 static void test_request_basic(sd_event *e)
58 sd_dhcp_client *client;
61 printf("* %s\n", __FUNCTION__);
63 r = sd_dhcp_client_new(&client);
68 r = sd_dhcp_client_attach_event(client, e, 0);
71 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
72 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
73 assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
75 assert_se(sd_dhcp_client_set_index(client, 15) == 0);
76 assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
77 assert_se(sd_dhcp_client_set_index(client, -1) == -EINVAL);
78 assert_se(sd_dhcp_client_set_index(client, 0) == -EINVAL);
79 assert_se(sd_dhcp_client_set_index(client, 1) == 0);
81 assert_se(sd_dhcp_client_set_request_option(client,
82 DHCP_OPTION_SUBNET_MASK) == -EEXIST);
83 assert_se(sd_dhcp_client_set_request_option(client,
84 DHCP_OPTION_ROUTER) == -EEXIST);
85 assert_se(sd_dhcp_client_set_request_option(client,
86 DHCP_OPTION_HOST_NAME) == -EEXIST);
87 assert_se(sd_dhcp_client_set_request_option(client,
88 DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
89 assert_se(sd_dhcp_client_set_request_option(client,
90 DHCP_OPTION_DOMAIN_NAME_SERVER)
92 assert_se(sd_dhcp_client_set_request_option(client,
93 DHCP_OPTION_NTP_SERVER) == -EEXIST);
95 assert_se(sd_dhcp_client_set_request_option(client,
96 DHCP_OPTION_PAD) == -EINVAL);
97 assert_se(sd_dhcp_client_set_request_option(client,
98 DHCP_OPTION_END) == -EINVAL);
99 assert_se(sd_dhcp_client_set_request_option(client,
100 DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
101 assert_se(sd_dhcp_client_set_request_option(client,
102 DHCP_OPTION_OVERLOAD) == -EINVAL);
103 assert_se(sd_dhcp_client_set_request_option(client,
104 DHCP_OPTION_PARAMETER_REQUEST_LIST)
107 assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
108 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
109 assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
110 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
112 sd_dhcp_client_unref(client);
115 static void test_checksum(void)
118 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
119 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0xff, 0xff, 0xff, 0xff
124 printf("* %s\n", __FUNCTION__);
126 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
129 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
133 case DHCP_OPTION_CLIENT_IDENTIFIER:
139 assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0);
140 assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, &iaid) >= 0);
142 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
143 assert_se(len == 19);
144 assert_se(option[0] == 0xff);
146 assert_se(memcmp(&option[1], &iaid, sizeof(iaid)) == 0);
147 assert_se(memcmp(&option[5], &duid, duid_len) == 0);
158 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
159 const void *packet, size_t len)
162 _cleanup_free_ DHCPPacket *discover;
163 uint16_t ip_check, udp_check;
168 size = sizeof(DHCPPacket);
169 assert_se(len > size);
171 discover = memdup(packet, len);
173 assert_se(discover->ip.ttl == IPDEFTTL);
174 assert_se(discover->ip.protocol == IPPROTO_UDP);
175 assert_se(discover->ip.saddr == INADDR_ANY);
176 assert_se(discover->ip.daddr == INADDR_BROADCAST);
177 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
178 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
180 ip_check = discover->ip.check;
182 discover->ip.ttl = 0;
183 discover->ip.check = discover->udp.len;
185 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
186 assert_se(udp_check == 0xffff);
188 discover->ip.ttl = IPDEFTTL;
189 discover->ip.check = ip_check;
191 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
192 assert_se(ip_check == 0xffff);
194 assert_se(discover->dhcp.xid);
195 assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
197 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
199 assert_se(callback_recv);
200 callback_recv(size, &discover->dhcp);
205 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
206 uint32_t id, const uint8_t *addr,
207 size_t addr_len, uint16_t arp_type)
209 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
215 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
219 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
226 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
227 const void *packet, size_t len)
232 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
236 res = dhcp_option_parse(dhcp, size, check_options, NULL);
237 assert_se(res == DHCP_DISCOVER);
240 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
245 static void test_discover_message(sd_event *e)
247 sd_dhcp_client *client;
251 printf("* %s\n", __FUNCTION__);
253 r = sd_dhcp_client_new(&client);
257 r = sd_dhcp_client_attach_event(client, e, 0);
260 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
261 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
263 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
265 callback_recv = test_discover_message_verify;
267 res = sd_dhcp_client_start(client);
269 assert_se(res == 0 || res == -EINPROGRESS);
271 sd_event_run(e, (uint64_t) -1);
273 sd_dhcp_client_stop(client);
274 sd_dhcp_client_unref(client);
276 test_fd[1] = safe_close(test_fd[1]);
278 callback_recv = NULL;
281 static uint8_t test_addr_acq_offer[] = {
282 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
283 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
284 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
285 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
286 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
288 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
316 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
317 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
318 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
319 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
320 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
321 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 static uint8_t test_addr_acq_ack[] = {
326 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
327 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
328 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
329 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
332 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
360 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
361 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
362 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
363 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
364 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
365 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
371 sd_event *e = userdata;
372 sd_dhcp_lease *lease;
376 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
378 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
381 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
382 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
383 sizeof(addr.s_addr)) == 0);
385 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
386 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
387 sizeof(addr.s_addr)) == 0);
389 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
390 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
391 sizeof(addr.s_addr)) == 0);
394 printf(" DHCP address acquired\n");
396 sd_dhcp_lease_unref(lease);
400 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
401 uint16_t udp_check = 0;
402 uint8_t *msg_bytes = (uint8_t *)request;
405 res = dhcp_option_parse(request, size, check_options, NULL);
406 assert_se(res == DHCP_REQUEST);
407 assert_se(xid == request->xid);
409 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
412 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
414 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
415 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
416 memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
418 callback_recv = NULL;
420 res = write(test_fd[1], test_addr_acq_ack,
421 sizeof(test_addr_acq_ack));
422 assert_se(res == sizeof(test_addr_acq_ack));
425 printf(" send DHCP Ack\n");
430 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
431 uint16_t udp_check = 0;
432 uint8_t *msg_bytes = (uint8_t *)discover;
435 res = dhcp_option_parse(discover, size, check_options, NULL);
436 assert_se(res == DHCP_DISCOVER);
438 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
443 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
445 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
446 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
447 memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
449 callback_recv = test_addr_acq_recv_request;
451 res = write(test_fd[1], test_addr_acq_offer,
452 sizeof(test_addr_acq_offer));
453 assert_se(res == sizeof(test_addr_acq_offer));
456 printf(" sent DHCP Offer\n");
461 static void test_addr_acq(sd_event *e) {
462 usec_t time_now = now(clock_boottime_or_monotonic());
463 sd_dhcp_client *client;
467 printf("* %s\n", __FUNCTION__);
469 r = sd_dhcp_client_new(&client);
473 r = sd_dhcp_client_attach_event(client, e, 0);
476 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
477 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
479 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
481 callback_recv = test_addr_acq_recv_discover;
483 assert_se(sd_event_add_time(e, &test_hangcheck,
484 clock_boottime_or_monotonic(),
485 time_now + 2 * USEC_PER_SEC, 0,
486 test_dhcp_hangcheck, NULL) >= 0);
488 res = sd_dhcp_client_start(client);
489 assert_se(res == 0 || res == -EINPROGRESS);
491 assert_se(sd_event_loop(e) >= 0);
493 test_hangcheck = sd_event_source_unref(test_hangcheck);
495 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
496 assert_se(sd_dhcp_client_stop(client) >= 0);
497 sd_dhcp_client_unref(client);
499 test_fd[1] = safe_close(test_fd[1]);
501 callback_recv = NULL;
505 int main(int argc, char *argv[]) {
506 _cleanup_event_unref_ sd_event *e;
508 log_set_max_level(LOG_DEBUG);
509 log_parse_environment();
512 assert_se(sd_event_new(&e) >= 0);
514 test_request_basic(e);
517 test_discover_message(e);
521 /* Make sure the async_close thread has finished.
522 * valgrind would report some of the phread_* structures
523 * as not cleaned up properly. */