]> git.proxmox.com Git - systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
Imported Upstream version 217
[systemd.git] / src / libsystemd-network / test-dhcp-client.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2013 Intel Corporation. All rights reserved.
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29
30 #include "util.h"
31 #include "socket-util.h"
32 #include "sd-event.h"
33 #include "event-util.h"
34
35 #include "dhcp-protocol.h"
36 #include "dhcp-internal.h"
37 #include "sd-dhcp-client.h"
38
39 static struct ether_addr mac_addr = {
40 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
41 };
42
43 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
44
45 static bool verbose = false;
46 static int test_fd[2];
47 static test_callback_recv_t callback_recv;
48 static be32_t xid;
49 static sd_event_source *test_hangcheck;
50
51 static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
52 void *userdata)
53 {
54 assert_not_reached("Test case should have completed in 2 seconds");
55
56 return 0;
57 }
58
59 static void test_request_basic(sd_event *e)
60 {
61 int r;
62
63 sd_dhcp_client *client;
64
65 if (verbose)
66 printf("* %s\n", __FUNCTION__);
67
68 r = sd_dhcp_client_new(&client);
69
70 assert_se(r >= 0);
71 assert_se(client);
72
73 r = sd_dhcp_client_attach_event(client, e, 0);
74 assert_se(r >= 0);
75
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);
79
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);
85
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)
96 == -EEXIST);
97 assert_se(sd_dhcp_client_set_request_option(client,
98 DHCP_OPTION_NTP_SERVER) == -EEXIST);
99
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)
110 == -EINVAL);
111
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);
116
117 sd_dhcp_client_unref(client);
118 }
119
120 static void test_checksum(void)
121 {
122 uint8_t buf[20] = {
123 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
124 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0xff, 0xff, 0xff, 0xff
126 };
127
128 if (verbose)
129 printf("* %s\n", __FUNCTION__);
130
131 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
132 }
133
134 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
135 void *user_data)
136 {
137 switch(code) {
138 case DHCP_OPTION_CLIENT_IDENTIFIER:
139 assert_se(len == 7);
140 assert_se(option[0] == 0x01);
141 assert_se(memcmp(&option[1], &mac_addr, ETH_ALEN) == 0);
142 break;
143
144 default:
145 break;
146 }
147
148 return 0;
149 }
150
151 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
152 const void *packet, size_t len)
153 {
154 size_t size;
155 _cleanup_free_ DHCPPacket *discover;
156 uint16_t ip_check, udp_check;
157
158 assert_se(s >= 0);
159 assert_se(packet);
160
161 size = sizeof(DHCPPacket);
162 assert_se(len > size);
163
164 discover = memdup(packet, len);
165
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));
172
173 ip_check = discover->ip.check;
174
175 discover->ip.ttl = 0;
176 discover->ip.check = discover->udp.len;
177
178 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
179 assert_se(udp_check == 0xffff);
180
181 discover->ip.ttl = IPDEFTTL;
182 discover->ip.check = ip_check;
183
184 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
185 assert_se(ip_check == 0xffff);
186
187 assert_se(discover->dhcp.xid);
188 assert_se(memcmp(discover->dhcp.chaddr,
189 &mac_addr.ether_addr_octet, 6) == 0);
190
191 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
192
193 assert_se(callback_recv);
194 callback_recv(size, &discover->dhcp);
195
196 return 575;
197 }
198
199 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
200 uint32_t id, const uint8_t *addr,
201 size_t addr_len, uint16_t arp_type)
202 {
203 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
204 return -errno;
205
206 return test_fd[0];
207 }
208
209 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
210 {
211 return 0;
212 }
213
214 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
215 const void *packet, size_t len)
216 {
217 return 0;
218 }
219
220 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
221 {
222 int res;
223
224 res = dhcp_option_parse(dhcp, size, check_options, NULL);
225 assert_se(res == DHCP_DISCOVER);
226
227 if (verbose)
228 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
229
230 return 0;
231 }
232
233 static void test_discover_message(sd_event *e)
234 {
235 sd_dhcp_client *client;
236 int res, r;
237
238 if (verbose)
239 printf("* %s\n", __FUNCTION__);
240
241 r = sd_dhcp_client_new(&client);
242 assert_se(r >= 0);
243 assert_se(client);
244
245 r = sd_dhcp_client_attach_event(client, e, 0);
246 assert_se(r >= 0);
247
248 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
249 assert_se(sd_dhcp_client_set_mac(client,
250 (const uint8_t *) &mac_addr,
251 sizeof (mac_addr),
252 ARPHRD_ETHER) >= 0);
253
254 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
255
256 callback_recv = test_discover_message_verify;
257
258 res = sd_dhcp_client_start(client);
259
260 assert_se(res == 0 || res == -EINPROGRESS);
261
262 sd_event_run(e, (uint64_t) -1);
263
264 sd_dhcp_client_stop(client);
265 sd_dhcp_client_unref(client);
266
267 test_fd[1] = safe_close(test_fd[1]);
268
269 callback_recv = NULL;
270 }
271
272 static uint8_t test_addr_acq_offer[] = {
273 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
274 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
275 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
276 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
277 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
279 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
307 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
308 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
309 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
310 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
311 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
312 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 };
315
316 static uint8_t test_addr_acq_ack[] = {
317 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
318 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
319 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
320 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
323 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
351 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
352 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
353 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
354 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
355 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
356 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 };
359
360 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
361 void *userdata) {
362 sd_event *e = userdata;
363 sd_dhcp_lease *lease;
364 struct in_addr addr;
365
366 assert_se(client);
367 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
368
369 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
370 assert_se(lease);
371
372 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
373 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
374 sizeof(addr.s_addr)) == 0);
375
376 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
377 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
378 sizeof(addr.s_addr)) == 0);
379
380 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
381 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
382 sizeof(addr.s_addr)) == 0);
383
384 if (verbose)
385 printf(" DHCP address acquired\n");
386
387 sd_dhcp_lease_unref(lease);
388 sd_event_exit(e, 0);
389 }
390
391 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
392 uint16_t udp_check = 0;
393 uint8_t *msg_bytes = (uint8_t *)request;
394 int res;
395
396 res = dhcp_option_parse(request, size, check_options, NULL);
397 assert_se(res == DHCP_REQUEST);
398 assert_se(xid == request->xid);
399
400 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
401
402 if (verbose)
403 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
404
405 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
406 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
407 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
408 ETHER_ADDR_LEN);
409
410 callback_recv = NULL;
411
412 res = write(test_fd[1], test_addr_acq_ack,
413 sizeof(test_addr_acq_ack));
414 assert_se(res == sizeof(test_addr_acq_ack));
415
416 if (verbose)
417 printf(" send DHCP Ack\n");
418
419 return 0;
420 };
421
422 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
423 uint16_t udp_check = 0;
424 uint8_t *msg_bytes = (uint8_t *)discover;
425 int res;
426
427 res = dhcp_option_parse(discover, size, check_options, NULL);
428 assert_se(res == DHCP_DISCOVER);
429
430 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
431
432 xid = discover->xid;
433
434 if (verbose)
435 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
436
437 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
438 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
439 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
440 ETHER_ADDR_LEN);
441
442 callback_recv = test_addr_acq_recv_request;
443
444 res = write(test_fd[1], test_addr_acq_offer,
445 sizeof(test_addr_acq_offer));
446 assert_se(res == sizeof(test_addr_acq_offer));
447
448 if (verbose)
449 printf(" sent DHCP Offer\n");
450
451 return 0;
452 }
453
454 static void test_addr_acq(sd_event *e) {
455 usec_t time_now = now(clock_boottime_or_monotonic());
456 sd_dhcp_client *client;
457 int res, r;
458
459 if (verbose)
460 printf("* %s\n", __FUNCTION__);
461
462 r = sd_dhcp_client_new(&client);
463 assert_se(r >= 0);
464 assert_se(client);
465
466 r = sd_dhcp_client_attach_event(client, e, 0);
467 assert_se(r >= 0);
468
469 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
470 assert_se(sd_dhcp_client_set_mac(client,
471 (const uint8_t *) &mac_addr,
472 sizeof (mac_addr),
473 ARPHRD_ETHER) >= 0);
474
475 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
476 >= 0);
477
478 callback_recv = test_addr_acq_recv_discover;
479
480 assert_se(sd_event_add_time(e, &test_hangcheck,
481 clock_boottime_or_monotonic(),
482 time_now + 2 * USEC_PER_SEC, 0,
483 test_dhcp_hangcheck, NULL) >= 0);
484
485 res = sd_dhcp_client_start(client);
486 assert_se(res == 0 || res == -EINPROGRESS);
487
488 assert_se(sd_event_loop(e) >= 0);
489
490 test_hangcheck = sd_event_source_unref(test_hangcheck);
491
492 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
493 assert_se(sd_dhcp_client_stop(client) >= 0);
494 sd_dhcp_client_unref(client);
495
496 test_fd[1] = safe_close(test_fd[1]);
497
498 callback_recv = NULL;
499 xid = 0;
500 }
501
502 int main(int argc, char *argv[]) {
503 _cleanup_event_unref_ sd_event *e;
504
505 log_set_max_level(LOG_DEBUG);
506 log_parse_environment();
507 log_open();
508
509 assert_se(sd_event_new(&e) >= 0);
510
511 test_request_basic(e);
512 test_checksum();
513
514 test_discover_message(e);
515 test_addr_acq(e);
516
517 return 0;
518 }