]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
sd-dhcp: checksum - make endianess-neutral
[thirdparty/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, uint32_t id)
200 {
201 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
202 return -errno;
203
204 return test_fd[0];
205 }
206
207 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
208 {
209 return 0;
210 }
211
212 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
213 const void *packet, size_t len)
214 {
215 return 0;
216 }
217
218 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
219 {
220 int res;
221
222 res = dhcp_option_parse(dhcp, size, check_options, NULL);
223 assert_se(res == DHCP_DISCOVER);
224
225 if (verbose)
226 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
227
228 return 0;
229 }
230
231 static void test_discover_message(sd_event *e)
232 {
233 sd_dhcp_client *client;
234 int res, r;
235
236 if (verbose)
237 printf("* %s\n", __FUNCTION__);
238
239 r = sd_dhcp_client_new(&client);
240 assert_se(r >= 0);
241 assert_se(client);
242
243 r = sd_dhcp_client_attach_event(client, e, 0);
244 assert_se(r >= 0);
245
246 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
247 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
248
249 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
250
251 callback_recv = test_discover_message_verify;
252
253 res = sd_dhcp_client_start(client);
254
255 assert_se(res == 0 || res == -EINPROGRESS);
256
257 sd_event_run(e, (uint64_t) -1);
258
259 sd_dhcp_client_stop(client);
260 sd_dhcp_client_unref(client);
261
262 test_fd[1] = safe_close(test_fd[1]);
263
264 callback_recv = NULL;
265 }
266
267 static uint8_t test_addr_acq_offer[] = {
268 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
269 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
270 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
271 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
272 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
274 0xc0, 0xa8, 0x02, 0x01, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
302 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
303 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
304 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
305 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
306 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
307 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 };
310
311 static uint8_t test_addr_acq_ack[] = {
312 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
313 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
314 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
315 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
318 0xc0, 0xa8, 0x02, 0x01, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
346 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
347 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
348 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
349 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
350 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
351 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 };
354
355 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
356 void *userdata) {
357 sd_event *e = userdata;
358 sd_dhcp_lease *lease;
359 struct in_addr addr;
360
361 assert_se(client);
362 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
363
364 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
365 assert_se(lease);
366
367 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
368 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
369 sizeof(addr.s_addr)) == 0);
370
371 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
372 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
373 sizeof(addr.s_addr)) == 0);
374
375 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
376 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
377 sizeof(addr.s_addr)) == 0);
378
379 if (verbose)
380 printf(" DHCP address acquired\n");
381
382 sd_dhcp_lease_unref(lease);
383 sd_event_exit(e, 0);
384 }
385
386 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
387 uint16_t udp_check = 0;
388 uint8_t *msg_bytes = (uint8_t *)request;
389 int res;
390
391 res = dhcp_option_parse(request, size, check_options, NULL);
392 assert_se(res == DHCP_REQUEST);
393 assert_se(xid == request->xid);
394
395 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
396
397 if (verbose)
398 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
399
400 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
401 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
402 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
403 ETHER_ADDR_LEN);
404
405 callback_recv = NULL;
406
407 res = write(test_fd[1], test_addr_acq_ack,
408 sizeof(test_addr_acq_ack));
409 assert_se(res == sizeof(test_addr_acq_ack));
410
411 if (verbose)
412 printf(" send DHCP Ack\n");
413
414 return 0;
415 };
416
417 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
418 uint16_t udp_check = 0;
419 uint8_t *msg_bytes = (uint8_t *)discover;
420 int res;
421
422 res = dhcp_option_parse(discover, size, check_options, NULL);
423 assert_se(res == DHCP_DISCOVER);
424
425 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
426
427 xid = discover->xid;
428
429 if (verbose)
430 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
431
432 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
433 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
434 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
435 ETHER_ADDR_LEN);
436
437 callback_recv = test_addr_acq_recv_request;
438
439 res = write(test_fd[1], test_addr_acq_offer,
440 sizeof(test_addr_acq_offer));
441 assert_se(res == sizeof(test_addr_acq_offer));
442
443 if (verbose)
444 printf(" sent DHCP Offer\n");
445
446 return 0;
447 }
448
449 static void test_addr_acq(sd_event *e) {
450 usec_t time_now = now(CLOCK_MONOTONIC);
451 sd_dhcp_client *client;
452 int res, r;
453
454 if (verbose)
455 printf("* %s\n", __FUNCTION__);
456
457 r = sd_dhcp_client_new(&client);
458 assert_se(r >= 0);
459 assert_se(client);
460
461 r = sd_dhcp_client_attach_event(client, e, 0);
462 assert_se(r >= 0);
463
464 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
465 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
466
467 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
468 >= 0);
469
470 callback_recv = test_addr_acq_recv_discover;
471
472 assert_se(sd_event_add_time(e, &test_hangcheck,
473 CLOCK_MONOTONIC,
474 time_now + 2 * USEC_PER_SEC, 0,
475 test_dhcp_hangcheck, NULL) >= 0);
476
477 res = sd_dhcp_client_start(client);
478 assert_se(res == 0 || res == -EINPROGRESS);
479
480 sd_event_loop(e);
481
482 test_hangcheck = sd_event_source_unref(test_hangcheck);
483
484 sd_dhcp_client_set_callback(client, NULL, NULL);
485 sd_dhcp_client_stop(client);
486 sd_dhcp_client_unref(client);
487
488 test_fd[1] = safe_close(test_fd[1]);
489
490 callback_recv = NULL;
491 xid = 0;
492 }
493
494 int main(int argc, char *argv[]) {
495 _cleanup_event_unref_ sd_event *e;
496
497 log_set_max_level(LOG_DEBUG);
498 log_parse_environment();
499 log_open();
500
501 assert_se(sd_event_new(&e) >= 0);
502
503 test_request_basic(e);
504 test_checksum();
505
506 test_discover_message(e);
507 test_addr_acq(e);
508
509 return 0;
510 }