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,
134 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
135 const void *packet, size_t len)
138 _cleanup_free_ DHCPPacket *discover;
139 uint16_t ip_check, udp_check;
144 size = sizeof(DHCPPacket) + 4;
145 assert_se(len > size);
147 discover = memdup(packet, len);
149 assert_se(discover->ip.ttl == IPDEFTTL);
150 assert_se(discover->ip.protocol == IPPROTO_UDP);
151 assert_se(discover->ip.saddr == INADDR_ANY);
152 assert_se(discover->ip.daddr == INADDR_BROADCAST);
153 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
154 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
156 ip_check = discover->ip.check;
158 discover->ip.ttl = 0;
159 discover->ip.check = discover->udp.len;
161 udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
162 assert_se(udp_check == 0xffff);
164 discover->ip.ttl = IPDEFTTL;
165 discover->ip.check = ip_check;
167 ip_check = ~dhcp_packet_checksum(&discover->ip, sizeof(discover->ip));
168 assert_se(ip_check == 0xffff);
170 assert_se(discover->dhcp.xid);
171 assert_se(memcmp(discover->dhcp.chaddr,
172 &mac_addr.ether_addr_octet, 6) == 0);
174 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
176 assert_se(callback_recv);
177 callback_recv(size, &discover->dhcp);
182 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
184 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
190 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
195 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
196 const void *packet, size_t len)
201 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
205 res = dhcp_option_parse(dhcp, size, check_options, NULL);
206 assert_se(res == DHCP_DISCOVER);
209 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
214 static void test_discover_message(sd_event *e)
216 sd_dhcp_client *client;
220 printf("* %s\n", __FUNCTION__);
222 r = sd_dhcp_client_new(&client);
226 r = sd_dhcp_client_attach_event(client, e, 0);
229 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
230 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
232 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
234 callback_recv = test_discover_message_verify;
236 res = sd_dhcp_client_start(client);
238 assert_se(res == 0 || res == -EINPROGRESS);
240 sd_event_run(e, (uint64_t) -1);
242 sd_dhcp_client_stop(client);
243 sd_dhcp_client_free(client);
248 callback_recv = NULL;
251 static uint8_t test_addr_acq_offer[] = {
252 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
253 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
254 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
255 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
256 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
257 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
258 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
286 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
287 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
288 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
289 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
290 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
291 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 static uint8_t test_addr_acq_ack[] = {
296 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
297 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
298 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
299 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
302 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
330 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
331 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
332 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
333 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
334 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
335 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
342 sd_event *e = userdata;
343 sd_dhcp_lease *lease;
347 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
349 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
352 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
353 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
354 sizeof(addr.s_addr)) == 0);
356 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
357 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
358 sizeof(addr.s_addr)) == 0);
360 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
361 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
362 sizeof(addr.s_addr)) == 0);
365 printf(" DHCP address acquired\n");
370 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request)
372 uint16_t udp_check = 0;
375 res = dhcp_option_parse(request, size, check_options, NULL);
376 assert_se(res == DHCP_REQUEST);
377 assert_se(xid == request->xid);
380 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
382 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
383 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
384 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
387 callback_recv = NULL;
389 res = write(test_fd[1], test_addr_acq_ack,
390 sizeof(test_addr_acq_ack));
391 assert_se(res == sizeof(test_addr_acq_ack));
394 printf(" send DHCP Ack\n");
399 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover)
401 uint16_t udp_check = 0;
404 res = dhcp_option_parse(discover, size, check_options, NULL);
405 assert_se(res == DHCP_DISCOVER);
410 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
412 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
413 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
414 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
417 callback_recv = test_addr_acq_recv_request;
419 res = write(test_fd[1], test_addr_acq_offer,
420 sizeof(test_addr_acq_offer));
421 assert_se(res == sizeof(test_addr_acq_offer));
424 printf(" send DHCP Offer\n");
429 static void test_addr_acq(sd_event *e)
431 usec_t time_now = now(CLOCK_MONOTONIC);
432 sd_dhcp_client *client;
436 printf("* %s\n", __FUNCTION__);
438 r = sd_dhcp_client_new(&client);
442 r = sd_dhcp_client_attach_event(client, e, 0);
445 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
446 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
448 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
451 callback_recv = test_addr_acq_recv_discover;
453 assert_se(sd_event_add_monotonic(e, &test_hangcheck,
454 time_now + 2 * USEC_PER_SEC, 0,
455 test_dhcp_hangcheck, NULL) >= 0);
457 res = sd_dhcp_client_start(client);
458 assert_se(res == 0 || res == -EINPROGRESS);
462 test_hangcheck = sd_event_source_unref(test_hangcheck);
464 sd_dhcp_client_set_callback(client, NULL, NULL);
465 sd_dhcp_client_stop(client);
466 sd_dhcp_client_free(client);
471 callback_recv = NULL;
475 int main(int argc, char *argv[])
479 assert_se(sd_event_new(&e) >= 0);
481 test_request_basic(e);
484 test_discover_message(e);