chiark / gitweb /
libsystemd-network: Export checksum function to test case
[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
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "sd-dhcp-client.h"
36
37 static struct ether_addr mac_addr = {
38         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
39 };
40
41 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
42
43 static bool verbose = false;
44 static int test_fd[2];
45 static test_callback_recv_t callback_recv;
46 static be32_t xid;
47
48 static void test_request_basic(sd_event *e)
49 {
50         int r;
51
52         sd_dhcp_client *client;
53
54         if (verbose)
55                 printf("* %s\n", __FUNCTION__);
56
57         r = sd_dhcp_client_new(&client);
58
59         assert_se(r >= 0);
60         assert_se(client);
61
62         r = sd_dhcp_client_attach_event(client, e, 0);
63         assert_se(r >= 0);
64
65         assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
66         assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
67         assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
68
69         assert_se(sd_dhcp_client_set_index(client, 15) == 0);
70         assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
71         assert_se(sd_dhcp_client_set_index(client, -1) == 0);
72
73         assert_se(sd_dhcp_client_set_request_option(client,
74                                         DHCP_OPTION_SUBNET_MASK) == -EEXIST);
75         assert_se(sd_dhcp_client_set_request_option(client,
76                                         DHCP_OPTION_ROUTER) == -EEXIST);
77         assert_se(sd_dhcp_client_set_request_option(client,
78                                         DHCP_OPTION_HOST_NAME) == -EEXIST);
79         assert_se(sd_dhcp_client_set_request_option(client,
80                                         DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
81         assert_se(sd_dhcp_client_set_request_option(client,
82                                         DHCP_OPTION_DOMAIN_NAME_SERVER)
83                         == -EEXIST);
84         assert_se(sd_dhcp_client_set_request_option(client,
85                                         DHCP_OPTION_NTP_SERVER) == -EEXIST);
86
87         assert_se(sd_dhcp_client_set_request_option(client,
88                                         DHCP_OPTION_PAD) == -EINVAL);
89         assert_se(sd_dhcp_client_set_request_option(client,
90                                         DHCP_OPTION_END) == -EINVAL);
91         assert_se(sd_dhcp_client_set_request_option(client,
92                                         DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
93         assert_se(sd_dhcp_client_set_request_option(client,
94                                         DHCP_OPTION_OVERLOAD) == -EINVAL);
95         assert_se(sd_dhcp_client_set_request_option(client,
96                                         DHCP_OPTION_PARAMETER_REQUEST_LIST)
97                         == -EINVAL);
98
99         assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
100         assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
101         assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
102         assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
103 }
104
105 static void test_checksum(void)
106 {
107         uint8_t buf[20] = {
108                 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
109                 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110                 0xff, 0xff, 0xff, 0xff
111         };
112
113         if (verbose)
114                 printf("* %s\n", __FUNCTION__);
115
116         assert_se(dhcp_packet_checksum(&buf, 20) == be16toh(0x78ae));
117 }
118
119 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
120                 void *user_data)
121 {
122         return 0;
123 }
124
125 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
126                                  const void *packet, size_t len)
127 {
128         size_t size;
129         _cleanup_free_ DHCPPacket *discover;
130         uint16_t ip_check, udp_check;
131
132         assert_se(s >= 0);
133         assert_se(packet);
134
135         size = sizeof(DHCPPacket) + 4;
136         assert_se(len > size);
137
138         discover = memdup(packet, len);
139
140         assert_se(discover->ip.ttl == IPDEFTTL);
141         assert_se(discover->ip.protocol == IPPROTO_UDP);
142         assert_se(discover->ip.saddr == INADDR_ANY);
143         assert_se(discover->ip.daddr == INADDR_BROADCAST);
144         assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
145         assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
146
147         ip_check = discover->ip.check;
148
149         discover->ip.ttl = 0;
150         discover->ip.check = discover->udp.len;
151
152         udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
153         assert_se(udp_check == 0xffff);
154
155         discover->ip.ttl = IPDEFTTL;
156         discover->ip.check = ip_check;
157
158         ip_check = ~dhcp_packet_checksum(&discover->ip, sizeof(discover->ip));
159         assert_se(ip_check == 0xffff);
160
161         assert_se(discover->dhcp.xid);
162         assert_se(memcmp(discover->dhcp.chaddr,
163                       &mac_addr.ether_addr_octet, 6) == 0);
164
165         size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
166
167         assert_se(callback_recv);
168         callback_recv(size, &discover->dhcp);
169
170         return 575;
171 }
172
173 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
174 {
175         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
176                 return -errno;
177
178         return test_fd[0];
179 }
180
181 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
182 {
183         return 0;
184 }
185
186 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
187                                  const void *packet, size_t len)
188 {
189         return 0;
190 }
191
192 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
193 {
194         int res;
195
196         res = dhcp_option_parse(dhcp, size, check_options, NULL);
197         assert_se(res == DHCP_DISCOVER);
198
199         if (verbose)
200                 printf("  recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
201
202         return 0;
203 }
204
205 static void test_discover_message(sd_event *e)
206 {
207         sd_dhcp_client *client;
208         int res, r;
209
210         if (verbose)
211                 printf("* %s\n", __FUNCTION__);
212
213         r = sd_dhcp_client_new(&client);
214         assert_se(r >= 0);
215         assert_se(client);
216
217         r = sd_dhcp_client_attach_event(client, e, 0);
218         assert_se(r >= 0);
219
220         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
221         assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
222
223         assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
224
225         callback_recv = test_discover_message_verify;
226
227         res = sd_dhcp_client_start(client);
228
229         assert_se(res == 0 || res == -EINPROGRESS);
230
231         sd_event_run(e, (uint64_t) -1);
232
233         sd_dhcp_client_stop(client);
234         sd_dhcp_client_free(client);
235
236         close(test_fd[0]);
237         close(test_fd[1]);
238
239         callback_recv = NULL;
240 }
241
242 static uint8_t test_addr_acq_offer[] = {
243         0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
244         0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
245         0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
246         0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
247         0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
248         0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
249         0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
250         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258         0x00, 0x00, 0x00, 0x00, 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         0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
277         0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
278         0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
279         0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
280         0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
281         0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
282         0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 };
285
286 static uint8_t test_addr_acq_ack[] = {
287         0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
288         0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
289         0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
290         0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
291         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
292         0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
293         0xc0, 0xa8, 0x02, 0x01, 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         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         0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
321         0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
322         0x00, 0x02, 0x58, 0x01, 0x04,   0xff, 0xff, 0xff,
323         0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
324         0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
325         0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
326         0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 };
329
330 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
331                                    void *userdata)
332 {
333         sd_event *e = userdata;
334         sd_dhcp_lease *lease;
335         struct in_addr addr;
336
337         assert_se(client);
338         assert_se(event == DHCP_EVENT_IP_ACQUIRE);
339
340         assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
341         assert_se(lease);
342
343         assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
344         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
345                       sizeof(addr.s_addr)) == 0);
346
347         assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
348         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
349                       sizeof(addr.s_addr)) == 0);
350
351         assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
352         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
353                       sizeof(addr.s_addr)) == 0);
354
355         if (verbose)
356                 printf("  DHCP address acquired\n");
357
358         sd_event_exit(e, 0);
359 }
360
361 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request)
362 {
363         uint16_t udp_check = 0;
364         int res;
365
366         res = dhcp_option_parse(request, size, check_options, NULL);
367         assert_se(res == DHCP_REQUEST);
368         assert_se(xid == request->xid);
369
370         if (verbose)
371                 printf("  recv DHCP Request  0x%08x\n", be32toh(xid));
372
373         memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
374         memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
375         memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
376                ETHER_ADDR_LEN);
377
378         callback_recv = NULL;
379
380         res = write(test_fd[1], test_addr_acq_ack,
381                     sizeof(test_addr_acq_ack));
382         assert_se(res == sizeof(test_addr_acq_ack));
383
384         if (verbose)
385                 printf("  send DHCP Ack\n");
386
387         return 0;
388 };
389
390 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover)
391 {
392         uint16_t udp_check = 0;
393         int res;
394
395         res = dhcp_option_parse(discover, size, check_options, NULL);
396         assert_se(res == DHCP_DISCOVER);
397
398         xid = discover->xid;
399
400         if (verbose)
401                 printf("  recv DHCP Discover 0x%08x\n", be32toh(xid));
402
403         memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
404         memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
405         memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
406                ETHER_ADDR_LEN);
407
408         callback_recv = test_addr_acq_recv_request;
409
410         res = write(test_fd[1], test_addr_acq_offer,
411                     sizeof(test_addr_acq_offer));
412         assert_se(res == sizeof(test_addr_acq_offer));
413
414         if (verbose)
415                 printf("  send DHCP Offer\n");
416
417         return 0;
418 }
419
420 static void test_addr_acq(sd_event *e)
421 {
422         sd_dhcp_client *client;
423         int res, r;
424
425         if (verbose)
426                 printf("* %s\n", __FUNCTION__);
427
428         r = sd_dhcp_client_new(&client);
429         assert_se(r >= 0);
430         assert_se(client);
431
432         r = sd_dhcp_client_attach_event(client, e, 0);
433         assert_se(r >= 0);
434
435         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
436         assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
437
438         assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
439                 >= 0);
440
441         callback_recv = test_addr_acq_recv_discover;
442
443         res = sd_dhcp_client_start(client);
444         assert_se(res == 0 || res == -EINPROGRESS);
445
446         sd_event_loop(e);
447
448         sd_dhcp_client_set_callback(client, NULL, NULL);
449         sd_dhcp_client_stop(client);
450         sd_dhcp_client_free(client);
451
452         close(test_fd[0]);
453         close(test_fd[1]);
454
455         callback_recv = NULL;
456         xid = 0;
457 }
458
459 int main(int argc, char *argv[])
460 {
461         sd_event *e;
462
463         assert_se(sd_event_new(&e) >= 0);
464
465         test_request_basic(e);
466         test_checksum();
467
468         test_discover_message(e);
469         test_addr_acq(e);
470
471         return 0;
472 }