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 "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "sd-dhcp-client.h"
37 static struct ether_addr mac_addr = {
38 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
41 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
43 static bool verbose = false;
44 static int test_fd[2];
45 static test_callback_recv_t callback_recv;
47 static sd_event_source *test_hangcheck;
49 static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
52 assert_not_reached("Test case should have completed in 2 seconds");
57 static void test_request_basic(sd_event *e)
61 sd_dhcp_client *client;
64 printf("* %s\n", __FUNCTION__);
66 r = sd_dhcp_client_new(&client);
71 r = sd_dhcp_client_attach_event(client, e, 0);
74 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
75 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
76 assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
78 assert_se(sd_dhcp_client_set_index(client, 15) == 0);
79 assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
80 assert_se(sd_dhcp_client_set_index(client, -1) == 0);
82 assert_se(sd_dhcp_client_set_request_option(client,
83 DHCP_OPTION_SUBNET_MASK) == -EEXIST);
84 assert_se(sd_dhcp_client_set_request_option(client,
85 DHCP_OPTION_ROUTER) == -EEXIST);
86 assert_se(sd_dhcp_client_set_request_option(client,
87 DHCP_OPTION_HOST_NAME) == -EEXIST);
88 assert_se(sd_dhcp_client_set_request_option(client,
89 DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
90 assert_se(sd_dhcp_client_set_request_option(client,
91 DHCP_OPTION_DOMAIN_NAME_SERVER)
93 assert_se(sd_dhcp_client_set_request_option(client,
94 DHCP_OPTION_NTP_SERVER) == -EEXIST);
96 assert_se(sd_dhcp_client_set_request_option(client,
97 DHCP_OPTION_PAD) == -EINVAL);
98 assert_se(sd_dhcp_client_set_request_option(client,
99 DHCP_OPTION_END) == -EINVAL);
100 assert_se(sd_dhcp_client_set_request_option(client,
101 DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
102 assert_se(sd_dhcp_client_set_request_option(client,
103 DHCP_OPTION_OVERLOAD) == -EINVAL);
104 assert_se(sd_dhcp_client_set_request_option(client,
105 DHCP_OPTION_PARAMETER_REQUEST_LIST)
108 assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
109 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
110 assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
111 assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
114 static void test_checksum(void)
117 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
118 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0xff, 0xff, 0xff, 0xff
123 printf("* %s\n", __FUNCTION__);
125 assert_se(dhcp_packet_checksum(&buf, 20) == be16toh(0x78ae));
128 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
132 case DHCP_OPTION_CLIENT_IDENTIFIER:
134 assert_se(option[0] == 0x01);
135 assert_se(memcmp(&option[1], &mac_addr, ETH_ALEN) == 0);
145 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
146 const void *packet, size_t len)
149 _cleanup_free_ DHCPPacket *discover;
150 uint16_t ip_check, udp_check;
155 size = sizeof(DHCPPacket) + 4;
156 assert_se(len > size);
158 discover = memdup(packet, len);
160 assert_se(discover->ip.ttl == IPDEFTTL);
161 assert_se(discover->ip.protocol == IPPROTO_UDP);
162 assert_se(discover->ip.saddr == INADDR_ANY);
163 assert_se(discover->ip.daddr == INADDR_BROADCAST);
164 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
165 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
167 ip_check = discover->ip.check;
169 discover->ip.ttl = 0;
170 discover->ip.check = discover->udp.len;
172 udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
173 assert_se(udp_check == 0xffff);
175 discover->ip.ttl = IPDEFTTL;
176 discover->ip.check = ip_check;
178 ip_check = ~dhcp_packet_checksum(&discover->ip, sizeof(discover->ip));
179 assert_se(ip_check == 0xffff);
181 assert_se(discover->dhcp.xid);
182 assert_se(memcmp(discover->dhcp.chaddr,
183 &mac_addr.ether_addr_octet, 6) == 0);
185 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
187 assert_se(callback_recv);
188 callback_recv(size, &discover->dhcp);
193 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
195 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
201 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
206 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
207 const void *packet, size_t len)
212 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
216 res = dhcp_option_parse(dhcp, size, check_options, NULL);
217 assert_se(res == DHCP_DISCOVER);
220 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
225 static void test_discover_message(sd_event *e)
227 sd_dhcp_client *client;
231 printf("* %s\n", __FUNCTION__);
233 r = sd_dhcp_client_new(&client);
237 r = sd_dhcp_client_attach_event(client, e, 0);
240 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
241 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
243 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
245 callback_recv = test_discover_message_verify;
247 res = sd_dhcp_client_start(client);
249 assert_se(res == 0 || res == -EINPROGRESS);
251 sd_event_run(e, (uint64_t) -1);
253 sd_dhcp_client_stop(client);
254 sd_dhcp_client_free(client);
259 callback_recv = NULL;
262 static uint8_t test_addr_acq_offer[] = {
263 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
264 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
265 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
266 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
267 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
269 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
297 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
298 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
299 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
300 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
301 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
302 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 static uint8_t test_addr_acq_ack[] = {
307 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
308 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
309 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
310 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
313 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
341 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
342 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
343 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
344 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
345 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
346 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
353 sd_event *e = userdata;
354 sd_dhcp_lease *lease;
358 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
360 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
363 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
364 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
365 sizeof(addr.s_addr)) == 0);
367 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
368 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
369 sizeof(addr.s_addr)) == 0);
371 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
372 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
373 sizeof(addr.s_addr)) == 0);
376 printf(" DHCP address acquired\n");
381 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request)
383 uint16_t udp_check = 0;
384 uint8_t *msg_bytes = (uint8_t *)request;
387 res = dhcp_option_parse(request, size, check_options, NULL);
388 assert_se(res == DHCP_REQUEST);
389 assert_se(xid == request->xid);
391 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
394 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
396 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
397 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
398 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
401 callback_recv = NULL;
403 res = write(test_fd[1], test_addr_acq_ack,
404 sizeof(test_addr_acq_ack));
405 assert_se(res == sizeof(test_addr_acq_ack));
408 printf(" send DHCP Ack\n");
413 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover)
415 uint16_t udp_check = 0;
416 uint8_t *msg_bytes = (uint8_t *)discover;
419 res = dhcp_option_parse(discover, size, check_options, NULL);
420 assert_se(res == DHCP_DISCOVER);
422 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
427 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
429 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
430 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
431 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
434 callback_recv = test_addr_acq_recv_request;
436 res = write(test_fd[1], test_addr_acq_offer,
437 sizeof(test_addr_acq_offer));
438 assert_se(res == sizeof(test_addr_acq_offer));
441 printf(" send DHCP Offer\n");
446 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_monotonic(e, &test_hangcheck,
471 time_now + 2 * USEC_PER_SEC, 0,
472 test_dhcp_hangcheck, NULL) >= 0);
474 res = sd_dhcp_client_start(client);
475 assert_se(res == 0 || res == -EINPROGRESS);
479 test_hangcheck = sd_event_source_unref(test_hangcheck);
481 sd_dhcp_client_set_callback(client, NULL, NULL);
482 sd_dhcp_client_stop(client);
483 sd_dhcp_client_free(client);
488 callback_recv = NULL;
492 int main(int argc, char *argv[])
496 assert_se(sd_event_new(&e) >= 0);
498 test_request_basic(e);
501 test_discover_message(e);