chiark / gitweb /
test-dhcp-client: unref lease objects to make valgrind happy
[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) == 0);
83
84         assert_se(sd_dhcp_client_set_request_option(client,
85                                         DHCP_OPTION_SUBNET_MASK) == -EEXIST);
86         assert_se(sd_dhcp_client_set_request_option(client,
87                                         DHCP_OPTION_ROUTER) == -EEXIST);
88         assert_se(sd_dhcp_client_set_request_option(client,
89                                         DHCP_OPTION_HOST_NAME) == -EEXIST);
90         assert_se(sd_dhcp_client_set_request_option(client,
91                                         DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
92         assert_se(sd_dhcp_client_set_request_option(client,
93                                         DHCP_OPTION_DOMAIN_NAME_SERVER)
94                         == -EEXIST);
95         assert_se(sd_dhcp_client_set_request_option(client,
96                                         DHCP_OPTION_NTP_SERVER) == -EEXIST);
97
98         assert_se(sd_dhcp_client_set_request_option(client,
99                                         DHCP_OPTION_PAD) == -EINVAL);
100         assert_se(sd_dhcp_client_set_request_option(client,
101                                         DHCP_OPTION_END) == -EINVAL);
102         assert_se(sd_dhcp_client_set_request_option(client,
103                                         DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
104         assert_se(sd_dhcp_client_set_request_option(client,
105                                         DHCP_OPTION_OVERLOAD) == -EINVAL);
106         assert_se(sd_dhcp_client_set_request_option(client,
107                                         DHCP_OPTION_PARAMETER_REQUEST_LIST)
108                         == -EINVAL);
109
110         assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
111         assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
112         assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
113         assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
114
115         sd_dhcp_client_unref(client);
116 }
117
118 static void test_checksum(void)
119 {
120         uint8_t buf[20] = {
121                 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
122                 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123                 0xff, 0xff, 0xff, 0xff
124         };
125
126         if (verbose)
127                 printf("* %s\n", __FUNCTION__);
128
129         assert_se(dhcp_packet_checksum(&buf, 20) == be16toh(0x78ae));
130 }
131
132 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
133                 void *user_data)
134 {
135         switch(code) {
136         case DHCP_OPTION_CLIENT_IDENTIFIER:
137                 assert_se(len == 7);
138                 assert_se(option[0] == 0x01);
139                 assert_se(memcmp(&option[1], &mac_addr, ETH_ALEN) == 0);
140                 break;
141
142         default:
143                 break;
144         }
145
146         return 0;
147 }
148
149 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
150                                  const void *packet, size_t len)
151 {
152         size_t size;
153         _cleanup_free_ DHCPPacket *discover;
154         uint16_t ip_check, udp_check;
155
156         assert_se(s >= 0);
157         assert_se(packet);
158
159         size = sizeof(DHCPPacket);
160         assert_se(len > size);
161
162         discover = memdup(packet, len);
163
164         assert_se(discover->ip.ttl == IPDEFTTL);
165         assert_se(discover->ip.protocol == IPPROTO_UDP);
166         assert_se(discover->ip.saddr == INADDR_ANY);
167         assert_se(discover->ip.daddr == INADDR_BROADCAST);
168         assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
169         assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
170
171         ip_check = discover->ip.check;
172
173         discover->ip.ttl = 0;
174         discover->ip.check = discover->udp.len;
175
176         udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
177         assert_se(udp_check == 0xffff);
178
179         discover->ip.ttl = IPDEFTTL;
180         discover->ip.check = ip_check;
181
182         ip_check = ~dhcp_packet_checksum(&discover->ip, sizeof(discover->ip));
183         assert_se(ip_check == 0xffff);
184
185         assert_se(discover->dhcp.xid);
186         assert_se(memcmp(discover->dhcp.chaddr,
187                       &mac_addr.ether_addr_octet, 6) == 0);
188
189         size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
190
191         assert_se(callback_recv);
192         callback_recv(size, &discover->dhcp);
193
194         return 575;
195 }
196
197 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id)
198 {
199         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
200                 return -errno;
201
202         return test_fd[0];
203 }
204
205 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
206 {
207         return 0;
208 }
209
210 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
211                                  const void *packet, size_t len)
212 {
213         return 0;
214 }
215
216 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
217 {
218         int res;
219
220         res = dhcp_option_parse(dhcp, size, check_options, NULL);
221         assert_se(res == DHCP_DISCOVER);
222
223         if (verbose)
224                 printf("  recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
225
226         return 0;
227 }
228
229 static void test_discover_message(sd_event *e)
230 {
231         sd_dhcp_client *client;
232         int res, r;
233
234         if (verbose)
235                 printf("* %s\n", __FUNCTION__);
236
237         r = sd_dhcp_client_new(&client);
238         assert_se(r >= 0);
239         assert_se(client);
240
241         r = sd_dhcp_client_attach_event(client, e, 0);
242         assert_se(r >= 0);
243
244         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
245         assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
246
247         assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
248
249         callback_recv = test_discover_message_verify;
250
251         res = sd_dhcp_client_start(client);
252
253         assert_se(res == 0 || res == -EINPROGRESS);
254
255         sd_event_run(e, (uint64_t) -1);
256
257         sd_dhcp_client_stop(client);
258         sd_dhcp_client_unref(client);
259
260         test_fd[1] = safe_close(test_fd[1]);
261
262         callback_recv = NULL;
263 }
264
265 static uint8_t test_addr_acq_offer[] = {
266         0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
267         0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
268         0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
269         0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
270         0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
271         0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
272         0xc0, 0xa8, 0x02, 0x01, 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         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         0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
300         0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
301         0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
302         0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
303         0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
304         0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
305         0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 };
308
309 static uint8_t test_addr_acq_ack[] = {
310         0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
311         0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
312         0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
313         0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
314         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
315         0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
316         0xc0, 0xa8, 0x02, 0x01, 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         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         0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
344         0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
345         0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
346         0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
347         0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
348         0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
349         0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 };
352
353 static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
354                                    void *userdata) {
355         sd_event *e = userdata;
356         sd_dhcp_lease *lease;
357         struct in_addr addr;
358
359         assert_se(client);
360         assert_se(event == DHCP_EVENT_IP_ACQUIRE);
361
362         assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
363         assert_se(lease);
364
365         assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
366         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
367                       sizeof(addr.s_addr)) == 0);
368
369         assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
370         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
371                       sizeof(addr.s_addr)) == 0);
372
373         assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
374         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
375                       sizeof(addr.s_addr)) == 0);
376
377         if (verbose)
378                 printf("  DHCP address acquired\n");
379
380         sd_dhcp_lease_unref(lease);
381         sd_event_exit(e, 0);
382 }
383
384 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
385         uint16_t udp_check = 0;
386         uint8_t *msg_bytes = (uint8_t *)request;
387         int res;
388
389         res = dhcp_option_parse(request, size, check_options, NULL);
390         assert_se(res == DHCP_REQUEST);
391         assert_se(xid == request->xid);
392
393         assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
394
395         if (verbose)
396                 printf("  recv DHCP Request  0x%08x\n", be32toh(xid));
397
398         memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
399         memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
400         memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet,
401                ETHER_ADDR_LEN);
402
403         callback_recv = NULL;
404
405         res = write(test_fd[1], test_addr_acq_ack,
406                     sizeof(test_addr_acq_ack));
407         assert_se(res == sizeof(test_addr_acq_ack));
408
409         if (verbose)
410                 printf("  send DHCP Ack\n");
411
412         return 0;
413 };
414
415 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
416         uint16_t udp_check = 0;
417         uint8_t *msg_bytes = (uint8_t *)discover;
418         int res;
419
420         res = dhcp_option_parse(discover, size, check_options, NULL);
421         assert_se(res == DHCP_DISCOVER);
422
423         assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
424
425         xid = discover->xid;
426
427         if (verbose)
428                 printf("  recv DHCP Discover 0x%08x\n", be32toh(xid));
429
430         memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
431         memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
432         memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet,
433                ETHER_ADDR_LEN);
434
435         callback_recv = test_addr_acq_recv_request;
436
437         res = write(test_fd[1], test_addr_acq_offer,
438                     sizeof(test_addr_acq_offer));
439         assert_se(res == sizeof(test_addr_acq_offer));
440
441         if (verbose)
442                 printf("  sent DHCP Offer\n");
443
444         return 0;
445 }
446
447 static void test_addr_acq(sd_event *e) {
448         usec_t time_now = now(CLOCK_MONOTONIC);
449         sd_dhcp_client *client;
450         int res, r;
451
452         if (verbose)
453                 printf("* %s\n", __FUNCTION__);
454
455         r = sd_dhcp_client_new(&client);
456         assert_se(r >= 0);
457         assert_se(client);
458
459         r = sd_dhcp_client_attach_event(client, e, 0);
460         assert_se(r >= 0);
461
462         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
463         assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
464
465         assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
466                 >= 0);
467
468         callback_recv = test_addr_acq_recv_discover;
469
470         assert_se(sd_event_add_time(e, &test_hangcheck,
471                                     CLOCK_MONOTONIC,
472                                     time_now + 2 * USEC_PER_SEC, 0,
473                                     test_dhcp_hangcheck, NULL) >= 0);
474
475         res = sd_dhcp_client_start(client);
476         assert_se(res == 0 || res == -EINPROGRESS);
477
478         sd_event_loop(e);
479
480         test_hangcheck = sd_event_source_unref(test_hangcheck);
481
482         sd_dhcp_client_set_callback(client, NULL, NULL);
483         sd_dhcp_client_stop(client);
484         sd_dhcp_client_unref(client);
485
486         test_fd[1] = safe_close(test_fd[1]);
487
488         callback_recv = NULL;
489         xid = 0;
490 }
491
492 int main(int argc, char *argv[]) {
493         _cleanup_event_unref_ sd_event *e;
494
495         log_set_max_level(LOG_DEBUG);
496         log_parse_environment();
497         log_open();
498
499         assert_se(sd_event_new(&e) >= 0);
500
501         test_request_basic(e);
502         test_checksum();
503
504         test_discover_message(e);
505         test_addr_acq(e);
506
507         return 0;
508 }