]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/libsystemd-network/test-dhcp-client.c
backlight: unify error messages
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-client.c
... / ...
CommitLineData
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
33#include "dhcp-protocol.h"
34#include "dhcp-internal.h"
35#include "sd-dhcp-client.h"
36
37static struct ether_addr mac_addr = {
38 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
39};
40
41typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
42
43static bool verbose = false;
44static int test_fd[2];
45static test_callback_recv_t callback_recv;
46static be32_t xid;
47static sd_event_source *test_hangcheck;
48
49static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
50 void *userdata)
51{
52 assert_not_reached("Test case should have completed in 2 seconds");
53
54 return 0;
55}
56
57static void test_request_basic(sd_event *e)
58{
59 int r;
60
61 sd_dhcp_client *client;
62
63 if (verbose)
64 printf("* %s\n", __FUNCTION__);
65
66 r = sd_dhcp_client_new(&client);
67
68 assert_se(r >= 0);
69 assert_se(client);
70
71 r = sd_dhcp_client_attach_event(client, e, 0);
72 assert_se(r >= 0);
73
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);
77
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);
81
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)
92 == -EEXIST);
93 assert_se(sd_dhcp_client_set_request_option(client,
94 DHCP_OPTION_NTP_SERVER) == -EEXIST);
95
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)
106 == -EINVAL);
107
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);
112}
113
114static void test_checksum(void)
115{
116 uint8_t buf[20] = {
117 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
118 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0xff, 0xff, 0xff, 0xff
120 };
121
122 if (verbose)
123 printf("* %s\n", __FUNCTION__);
124
125 assert_se(dhcp_packet_checksum(&buf, 20) == be16toh(0x78ae));
126}
127
128static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
129 void *user_data)
130{
131 switch(code) {
132 case DHCP_OPTION_CLIENT_IDENTIFIER:
133 assert_se(len == 7);
134 assert_se(option[0] == 0x01);
135 assert_se(memcmp(&option[1], &mac_addr, ETH_ALEN) == 0);
136 break;
137
138 default:
139 break;
140 }
141
142 return 0;
143}
144
145int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
146 const void *packet, size_t len)
147{
148 size_t size;
149 _cleanup_free_ DHCPPacket *discover;
150 uint16_t ip_check, udp_check;
151
152 assert_se(s >= 0);
153 assert_se(packet);
154
155 size = sizeof(DHCPPacket) + 4;
156 assert_se(len > size);
157
158 discover = memdup(packet, len);
159
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));
166
167 ip_check = discover->ip.check;
168
169 discover->ip.ttl = 0;
170 discover->ip.check = discover->udp.len;
171
172 udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
173 assert_se(udp_check == 0xffff);
174
175 discover->ip.ttl = IPDEFTTL;
176 discover->ip.check = ip_check;
177
178 ip_check = ~dhcp_packet_checksum(&discover->ip, sizeof(discover->ip));
179 assert_se(ip_check == 0xffff);
180
181 assert_se(discover->dhcp.xid);
182 assert_se(memcmp(discover->dhcp.chaddr,
183 &mac_addr.ether_addr_octet, 6) == 0);
184
185 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
186
187 assert_se(callback_recv);
188 callback_recv(size, &discover->dhcp);
189
190 return 575;
191}
192
193int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id)
194{
195 if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
196 return -errno;
197
198 return test_fd[0];
199}
200
201int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
202{
203 return 0;
204}
205
206int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
207 const void *packet, size_t len)
208{
209 return 0;
210}
211
212static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
213{
214 int res;
215
216 res = dhcp_option_parse(dhcp, size, check_options, NULL);
217 assert_se(res == DHCP_DISCOVER);
218
219 if (verbose)
220 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
221
222 return 0;
223}
224
225static void test_discover_message(sd_event *e)
226{
227 sd_dhcp_client *client;
228 int res, r;
229
230 if (verbose)
231 printf("* %s\n", __FUNCTION__);
232
233 r = sd_dhcp_client_new(&client);
234 assert_se(r >= 0);
235 assert_se(client);
236
237 r = sd_dhcp_client_attach_event(client, e, 0);
238 assert_se(r >= 0);
239
240 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
241 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
242
243 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
244
245 callback_recv = test_discover_message_verify;
246
247 res = sd_dhcp_client_start(client);
248
249 assert_se(res == 0 || res == -EINPROGRESS);
250
251 sd_event_run(e, (uint64_t) -1);
252
253 sd_dhcp_client_stop(client);
254 sd_dhcp_client_free(client);
255
256 test_fd[1] = safe_close(test_fd[1]);
257
258 callback_recv = NULL;
259}
260
261static uint8_t test_addr_acq_offer[] = {
262 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
263 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
264 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
265 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
266 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
268 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
296 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
297 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
298 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
299 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
300 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
301 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303};
304
305static uint8_t test_addr_acq_ack[] = {
306 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
307 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
308 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
309 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
312 0xc0, 0xa8, 0x02, 0x01, 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 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
340 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
341 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
342 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
343 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
344 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
345 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347};
348
349static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
350 void *userdata)
351{
352 sd_event *e = userdata;
353 sd_dhcp_lease *lease;
354 struct in_addr addr;
355
356 assert_se(client);
357 assert_se(event == DHCP_EVENT_IP_ACQUIRE);
358
359 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
360 assert_se(lease);
361
362 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
363 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
364 sizeof(addr.s_addr)) == 0);
365
366 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
367 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
368 sizeof(addr.s_addr)) == 0);
369
370 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
371 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
372 sizeof(addr.s_addr)) == 0);
373
374 if (verbose)
375 printf(" DHCP address acquired\n");
376
377 sd_event_exit(e, 0);
378}
379
380static int test_addr_acq_recv_request(size_t size, DHCPMessage *request)
381{
382 uint16_t udp_check = 0;
383 uint8_t *msg_bytes = (uint8_t *)request;
384 int res;
385
386 res = dhcp_option_parse(request, size, check_options, NULL);
387 assert_se(res == DHCP_REQUEST);
388 assert_se(xid == request->xid);
389
390 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
391
392 if (verbose)
393 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
394
395 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
396 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
397 memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
398 ETHER_ADDR_LEN);
399
400 callback_recv = NULL;
401
402 res = write(test_fd[1], test_addr_acq_ack,
403 sizeof(test_addr_acq_ack));
404 assert_se(res == sizeof(test_addr_acq_ack));
405
406 if (verbose)
407 printf(" send DHCP Ack\n");
408
409 return 0;
410};
411
412static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover)
413{
414 uint16_t udp_check = 0;
415 uint8_t *msg_bytes = (uint8_t *)discover;
416 int res;
417
418 res = dhcp_option_parse(discover, size, check_options, NULL);
419 assert_se(res == DHCP_DISCOVER);
420
421 assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
422
423 xid = discover->xid;
424
425 if (verbose)
426 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
427
428 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
429 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
430 memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
431 ETHER_ADDR_LEN);
432
433 callback_recv = test_addr_acq_recv_request;
434
435 res = write(test_fd[1], test_addr_acq_offer,
436 sizeof(test_addr_acq_offer));
437 assert_se(res == sizeof(test_addr_acq_offer));
438
439 if (verbose)
440 printf(" send DHCP Offer\n");
441
442 return 0;
443}
444
445static void test_addr_acq(sd_event *e)
446{
447 usec_t time_now = now(CLOCK_MONOTONIC);
448 sd_dhcp_client *client;
449 int res, r;
450
451 if (verbose)
452 printf("* %s\n", __FUNCTION__);
453
454 r = sd_dhcp_client_new(&client);
455 assert_se(r >= 0);
456 assert_se(client);
457
458 r = sd_dhcp_client_attach_event(client, e, 0);
459 assert_se(r >= 0);
460
461 assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
462 assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
463
464 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
465 >= 0);
466
467 callback_recv = test_addr_acq_recv_discover;
468
469 assert_se(sd_event_add_time(e, &test_hangcheck,
470 CLOCK_MONOTONIC,
471 time_now + 2 * USEC_PER_SEC, 0,
472 test_dhcp_hangcheck, NULL) >= 0);
473
474 res = sd_dhcp_client_start(client);
475 assert_se(res == 0 || res == -EINPROGRESS);
476
477 sd_event_loop(e);
478
479 test_hangcheck = sd_event_source_unref(test_hangcheck);
480
481 sd_dhcp_client_set_callback(client, NULL, NULL);
482 sd_dhcp_client_stop(client);
483 sd_dhcp_client_free(client);
484
485 test_fd[1] = safe_close(test_fd[1]);
486
487 callback_recv = NULL;
488 xid = 0;
489}
490
491int main(int argc, char *argv[])
492{
493 sd_event *e;
494
495 assert_se(sd_event_new(&e) >= 0);
496
497 test_request_basic(e);
498 test_checksum();
499
500 test_discover_message(e);
501 test_addr_acq(e);
502
503 return 0;
504}