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) == 0);
84 assert_se(sd_dhcp_client_set_request_option(client,
85 DHCP_OPTION_SUBNET_MASK) == -EEXIST);
86 assert_se(sd_dhcp_client_set_request_option(client,
87 DHCP_OPTION_ROUTER) == -EEXIST);
88 assert_se(sd_dhcp_client_set_request_option(client,
89 DHCP_OPTION_HOST_NAME) == -EEXIST);
90 assert_se(sd_dhcp_client_set_request_option(client,
91 DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
92 assert_se(sd_dhcp_client_set_request_option(client,
93 DHCP_OPTION_DOMAIN_NAME_SERVER)
95 assert_se(sd_dhcp_client_set_request_option(client,
96 DHCP_OPTION_NTP_SERVER) == -EEXIST);
98 assert_se(sd_dhcp_client_set_request_option(client,
99 DHCP_OPTION_PAD) == -EINVAL);
100 assert_se(sd_dhcp_client_set_request_option(client,
101 DHCP_OPTION_END) == -EINVAL);
102 assert_se(sd_dhcp_client_set_request_option(client,
103 DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
104 assert_se(sd_dhcp_client_set_request_option(client,
105 DHCP_OPTION_OVERLOAD) == -EINVAL);
106 assert_se(sd_dhcp_client_set_request_option(client,
107 DHCP_OPTION_PARAMETER_REQUEST_LIST)
110 assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
111 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
112 assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
113 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
115 sd_dhcp_client_unref(client);
118 static void test_checksum(void)
121 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
122 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0xff, 0xff, 0xff, 0xff
127 printf("* %s\n", __FUNCTION__);
129 assert_se(dhcp_packet_checksum(&buf, 20) == be16toh(0x78ae));
132 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
136 case DHCP_OPTION_CLIENT_IDENTIFIER:
138 assert_se(option[0] == 0x01);
139 assert_se(memcmp(&option[1], &mac_addr, ETH_ALEN) == 0);
149 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
150 const void *packet, size_t len)
153 _cleanup_free_ DHCPPacket *discover;
154 uint16_t ip_check, udp_check;
159 size = sizeof(DHCPPacket);
160 assert_se(len > size);
162 discover = memdup(packet, len);
164 assert_se(discover->ip.ttl == IPDEFTTL);
165 assert_se(discover->ip.protocol == IPPROTO_UDP);
166 assert_se(discover->ip.saddr == INADDR_ANY);
167 assert_se(discover->ip.daddr == INADDR_BROADCAST);
168 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
169 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
171 ip_check = discover->ip.check;
173 discover->ip.ttl = 0;
174 discover->ip.check = discover->udp.len;
176 udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
177 assert_se(udp_check == 0xffff);
179 discover->ip.ttl = IPDEFTTL;
180 discover->ip.check = ip_check;
182 ip_check = ~dhcp_packet_checksum(&discover->ip, sizeof(discover->ip));
183 assert_se(ip_check == 0xffff);
185 assert_se(discover->dhcp.xid);
186 assert_se(memcmp(discover->dhcp.chaddr,
187 &mac_addr.ether_addr_octet, 6) == 0);
189 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
191 assert_se(callback_recv);
192 callback_recv(size, &discover->dhcp);
197 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id)
199 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
205 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
210 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
211 const void *packet, size_t len)
216 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
220 res = dhcp_option_parse(dhcp, size, check_options, NULL);
221 assert_se(res == DHCP_DISCOVER);
224 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
229 static void test_discover_message(sd_event *e)
231 sd_dhcp_client *client;
235 printf("* %s\n", __FUNCTION__);
237 r = sd_dhcp_client_new(&client);
241 r = sd_dhcp_client_attach_event(client, e, 0);
244 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
245 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
247 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
249 callback_recv = test_discover_message_verify;
251 res = sd_dhcp_client_start(client);
253 assert_se(res == 0 || res == -EINPROGRESS);
255 sd_event_run(e, (uint64_t) -1);
257 sd_dhcp_client_stop(client);
258 sd_dhcp_client_unref(client);
260 test_fd[1] = safe_close(test_fd[1]);
262 callback_recv = NULL;
265 static uint8_t test_addr_acq_offer[] = {
266 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
267 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
268 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
269 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
270 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
272 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
300 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
301 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
302 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
303 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
304 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
305 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 static uint8_t test_addr_acq_ack[] = {
310 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
311 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
312 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
313 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
316 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
344 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
345 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
346 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
347 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
348 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
349 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
355 sd_event *e = userdata;
356 sd_dhcp_lease *lease;
360 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
362 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
365 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
366 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
367 sizeof(addr.s_addr)) == 0);
369 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
370 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
371 sizeof(addr.s_addr)) == 0);
373 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
374 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
375 sizeof(addr.s_addr)) == 0);
378 printf(" DHCP address acquired\n");
380 sd_dhcp_lease_unref(lease);
384 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
385 uint16_t udp_check = 0;
386 uint8_t *msg_bytes = (uint8_t *)request;
389 res = dhcp_option_parse(request, size, check_options, NULL);
390 assert_se(res == DHCP_REQUEST);
391 assert_se(xid == request->xid);
393 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
396 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
398 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
399 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
400 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
403 callback_recv = NULL;
405 res = write(test_fd[1], test_addr_acq_ack,
406 sizeof(test_addr_acq_ack));
407 assert_se(res == sizeof(test_addr_acq_ack));
410 printf(" send DHCP Ack\n");
415 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
416 uint16_t udp_check = 0;
417 uint8_t *msg_bytes = (uint8_t *)discover;
420 res = dhcp_option_parse(discover, size, check_options, NULL);
421 assert_se(res == DHCP_DISCOVER);
423 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
428 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
430 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
431 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
432 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
435 callback_recv = test_addr_acq_recv_request;
437 res = write(test_fd[1], test_addr_acq_offer,
438 sizeof(test_addr_acq_offer));
439 assert_se(res == sizeof(test_addr_acq_offer));
442 printf(" sent DHCP Offer\n");
447 static void test_addr_acq(sd_event *e) {
448 usec_t time_now = now(CLOCK_MONOTONIC);
449 sd_dhcp_client *client;
453 printf("* %s\n", __FUNCTION__);
455 r = sd_dhcp_client_new(&client);
459 r = sd_dhcp_client_attach_event(client, e, 0);
462 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
463 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
465 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
468 callback_recv = test_addr_acq_recv_discover;
470 assert_se(sd_event_add_time(e, &test_hangcheck,
472 time_now + 2 * USEC_PER_SEC, 0,
473 test_dhcp_hangcheck, NULL) >= 0);
475 res = sd_dhcp_client_start(client);
476 assert_se(res == 0 || res == -EINPROGRESS);
480 test_hangcheck = sd_event_source_unref(test_hangcheck);
482 sd_dhcp_client_set_callback(client, NULL, NULL);
483 sd_dhcp_client_stop(client);
484 sd_dhcp_client_unref(client);
486 test_fd[1] = safe_close(test_fd[1]);
488 callback_recv = NULL;
492 int main(int argc, char *argv[]) {
493 _cleanup_event_unref_ sd_event *e;
495 log_set_max_level(LOG_DEBUG);
496 log_parse_environment();
499 assert_se(sd_event_new(&e) >= 0);
501 test_request_basic(e);
504 test_discover_message(e);