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, uint32_t id, struct ether_addr mac)
201 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
207 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
212 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
213 const void *packet, size_t len)
218 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
222 res = dhcp_option_parse(dhcp, size, check_options, NULL);
223 assert_se(res == DHCP_DISCOVER);
226 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
231 static void test_discover_message(sd_event *e)
233 sd_dhcp_client *client;
237 printf("* %s\n", __FUNCTION__);
239 r = sd_dhcp_client_new(&client);
243 r = sd_dhcp_client_attach_event(client, e, 0);
246 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
247 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
249 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
251 callback_recv = test_discover_message_verify;
253 res = sd_dhcp_client_start(client);
255 assert_se(res == 0 || res == -EINPROGRESS);
257 sd_event_run(e, (uint64_t) -1);
259 sd_dhcp_client_stop(client);
260 sd_dhcp_client_unref(client);
262 test_fd[1] = safe_close(test_fd[1]);
264 callback_recv = NULL;
267 static uint8_t test_addr_acq_offer[] = {
268 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
269 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
270 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
271 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
272 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
274 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
302 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
303 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
304 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
305 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
306 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
307 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 static uint8_t test_addr_acq_ack[] = {
312 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
313 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
314 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
315 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
318 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
346 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
347 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
348 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
349 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
350 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
351 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
357 sd_event *e = userdata;
358 sd_dhcp_lease *lease;
362 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
364 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
367 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
368 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
369 sizeof(addr.s_addr)) == 0);
371 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
372 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
373 sizeof(addr.s_addr)) == 0);
375 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
376 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
377 sizeof(addr.s_addr)) == 0);
380 printf(" DHCP address acquired\n");
382 sd_dhcp_lease_unref(lease);
386 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
387 uint16_t udp_check = 0;
388 uint8_t *msg_bytes = (uint8_t *)request;
391 res = dhcp_option_parse(request, size, check_options, NULL);
392 assert_se(res == DHCP_REQUEST);
393 assert_se(xid == request->xid);
395 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
398 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
400 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
401 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
402 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
405 callback_recv = NULL;
407 res = write(test_fd[1], test_addr_acq_ack,
408 sizeof(test_addr_acq_ack));
409 assert_se(res == sizeof(test_addr_acq_ack));
412 printf(" send DHCP Ack\n");
417 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
418 uint16_t udp_check = 0;
419 uint8_t *msg_bytes = (uint8_t *)discover;
422 res = dhcp_option_parse(discover, size, check_options, NULL);
423 assert_se(res == DHCP_DISCOVER);
425 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
430 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
432 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
433 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
434 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
437 callback_recv = test_addr_acq_recv_request;
439 res = write(test_fd[1], test_addr_acq_offer,
440 sizeof(test_addr_acq_offer));
441 assert_se(res == sizeof(test_addr_acq_offer));
444 printf(" sent DHCP Offer\n");
449 static void test_addr_acq(sd_event *e) {
450 usec_t time_now = now(clock_boottime_or_monotonic());
451 sd_dhcp_client *client;
455 printf("* %s\n", __FUNCTION__);
457 r = sd_dhcp_client_new(&client);
461 r = sd_dhcp_client_attach_event(client, e, 0);
464 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
465 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
467 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
470 callback_recv = test_addr_acq_recv_discover;
472 assert_se(sd_event_add_time(e, &test_hangcheck,
473 clock_boottime_or_monotonic(),
474 time_now + 2 * USEC_PER_SEC, 0,
475 test_dhcp_hangcheck, NULL) >= 0);
477 res = sd_dhcp_client_start(client);
478 assert_se(res == 0 || res == -EINPROGRESS);
482 test_hangcheck = sd_event_source_unref(test_hangcheck);
484 sd_dhcp_client_set_callback(client, NULL, NULL);
485 sd_dhcp_client_stop(client);
486 sd_dhcp_client_unref(client);
488 test_fd[1] = safe_close(test_fd[1]);
490 callback_recv = NULL;
494 int main(int argc, char *argv[]) {
495 _cleanup_event_unref_ sd_event *e;
497 log_set_max_level(LOG_DEBUG);
498 log_parse_environment();
501 assert_se(sd_event_new(&e) >= 0);
503 test_request_basic(e);
506 test_discover_message(e);