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)
224 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
225 const void *packet, size_t len)
230 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
234 res = dhcp_option_parse(dhcp, size, check_options, NULL);
235 assert_se(res == DHCP_DISCOVER);
238 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
243 static void test_discover_message(sd_event *e)
245 sd_dhcp_client *client;
249 printf("* %s\n", __FUNCTION__);
251 r = sd_dhcp_client_new(&client);
255 r = sd_dhcp_client_attach_event(client, e, 0);
258 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
259 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
261 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
263 callback_recv = test_discover_message_verify;
265 res = sd_dhcp_client_start(client);
267 assert_se(res == 0 || res == -EINPROGRESS);
269 sd_event_run(e, (uint64_t) -1);
271 sd_dhcp_client_stop(client);
272 sd_dhcp_client_unref(client);
274 test_fd[1] = safe_close(test_fd[1]);
276 callback_recv = NULL;
279 static uint8_t test_addr_acq_offer[] = {
280 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
281 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
282 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
283 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
284 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
286 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
314 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
315 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
316 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
317 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
318 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
319 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 static uint8_t test_addr_acq_ack[] = {
324 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
325 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
326 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
327 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
330 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
358 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
359 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
360 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
361 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
362 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
363 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
369 sd_event *e = userdata;
370 sd_dhcp_lease *lease;
374 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
376 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
379 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
380 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
381 sizeof(addr.s_addr)) == 0);
383 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
384 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
385 sizeof(addr.s_addr)) == 0);
387 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
388 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
389 sizeof(addr.s_addr)) == 0);
392 printf(" DHCP address acquired\n");
394 sd_dhcp_lease_unref(lease);
398 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
399 uint16_t udp_check = 0;
400 uint8_t *msg_bytes = (uint8_t *)request;
403 res = dhcp_option_parse(request, size, check_options, NULL);
404 assert_se(res == DHCP_REQUEST);
405 assert_se(xid == request->xid);
407 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
410 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
412 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
413 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
414 memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
416 callback_recv = NULL;
418 res = write(test_fd[1], test_addr_acq_ack,
419 sizeof(test_addr_acq_ack));
420 assert_se(res == sizeof(test_addr_acq_ack));
423 printf(" send DHCP Ack\n");
428 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
429 uint16_t udp_check = 0;
430 uint8_t *msg_bytes = (uint8_t *)discover;
433 res = dhcp_option_parse(discover, size, check_options, NULL);
434 assert_se(res == DHCP_DISCOVER);
436 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
441 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
443 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
444 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
445 memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
447 callback_recv = test_addr_acq_recv_request;
449 res = write(test_fd[1], test_addr_acq_offer,
450 sizeof(test_addr_acq_offer));
451 assert_se(res == sizeof(test_addr_acq_offer));
454 printf(" sent DHCP Offer\n");
459 static void test_addr_acq(sd_event *e) {
460 usec_t time_now = now(clock_boottime_or_monotonic());
461 sd_dhcp_client *client;
465 printf("* %s\n", __FUNCTION__);
467 r = sd_dhcp_client_new(&client);
471 r = sd_dhcp_client_attach_event(client, e, 0);
474 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
475 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
477 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
479 callback_recv = test_addr_acq_recv_discover;
481 assert_se(sd_event_add_time(e, &test_hangcheck,
482 clock_boottime_or_monotonic(),
483 time_now + 2 * USEC_PER_SEC, 0,
484 test_dhcp_hangcheck, NULL) >= 0);
486 res = sd_dhcp_client_start(client);
487 assert_se(res == 0 || res == -EINPROGRESS);
489 assert_se(sd_event_loop(e) >= 0);
491 test_hangcheck = sd_event_source_unref(test_hangcheck);
493 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
494 assert_se(sd_dhcp_client_stop(client) >= 0);
495 sd_dhcp_client_unref(client);
497 test_fd[1] = safe_close(test_fd[1]);
499 callback_recv = NULL;
503 int main(int argc, char *argv[]) {
504 _cleanup_event_unref_ sd_event *e;
506 log_set_max_level(LOG_DEBUG);
507 log_parse_environment();
510 assert_se(sd_event_new(&e) >= 0);
512 test_request_basic(e);
515 test_discover_message(e);