chiark / gitweb /
sd-lldp: minor header cleanup
[elogind.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 }