chiark / gitweb /
sd-dhcp6-client: fix free before use
[elogind.git] / src / libsystemd-network / test-dhcp-server.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   Copyright (C) 2014 Tom Gundersen
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <netinet/if_ether.h>
24 #include <assert.h>
25 #include <errno.h>
26
27 #include "sd-event.h"
28 #include "event-util.h"
29
30 #include "sd-dhcp-server.h"
31 #include "dhcp-server-internal.h"
32
33 static int test_basic(sd_event *event) {
34         _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
35         struct in_addr address_lo = {
36                 .s_addr = htonl(INADDR_LOOPBACK),
37         };
38         struct in_addr address_any = {
39                 .s_addr = htonl(INADDR_ANY),
40         };
41         int r;
42
43         /* attach to loopback interface */
44         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
45         assert_se(server);
46
47         assert_se(sd_dhcp_server_attach_event(server, event, 0) >= 0);
48         assert_se(sd_dhcp_server_attach_event(server, event, 0) == -EBUSY);
49         assert_se(sd_dhcp_server_get_event(server) == event);
50         assert_se(sd_dhcp_server_detach_event(server) >= 0);
51         assert_se(!sd_dhcp_server_get_event(server));
52         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
53         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) == -EBUSY);
54
55         assert_se(sd_dhcp_server_ref(server) == server);
56         assert_se(!sd_dhcp_server_unref(server));
57
58         assert_se(sd_dhcp_server_start(server) == -EUNATCH);
59         assert_se(sd_dhcp_server_set_address(server, &address_any) == -EINVAL);
60         assert_se(sd_dhcp_server_set_address(server, &address_lo) >= 0);
61         assert_se(sd_dhcp_server_set_address(server, &address_lo) == -EBUSY);
62
63         assert_se(sd_dhcp_server_set_lease_pool(server, &address_any, 1) == -EINVAL);
64         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 0) == -EINVAL);
65         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) >= 0);
66         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) == -EBUSY);
67
68         r = sd_dhcp_server_start(server);
69
70         if (r == -EPERM)
71                 return EXIT_TEST_SKIP;
72         assert_se(r >= 0);
73
74         assert_se(sd_dhcp_server_start(server) == -EBUSY);
75         assert_se(sd_dhcp_server_stop(server) >= 0);
76         assert_se(sd_dhcp_server_stop(server) >= 0);
77         assert_se(sd_dhcp_server_start(server) >= 0);
78
79         return 0;
80 }
81
82 static void test_message_handler(void) {
83         _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
84         struct {
85                 DHCPMessage message;
86                 struct {
87                         uint8_t code;
88                         uint8_t length;
89                         uint8_t type;
90                 } _packed_ option_type;
91                 struct {
92                         uint8_t code;
93                         uint8_t length;
94                         be32_t address;
95                 } _packed_ option_requested_ip;
96                 struct {
97                         uint8_t code;
98                         uint8_t length;
99                         be32_t address;
100                 } _packed_ option_server_id;
101                 struct {
102                         uint8_t code;
103                         uint8_t length;
104                         uint8_t id[7];
105                 } _packed_ option_client_id;
106                 uint8_t end;
107         } _packed_ test = {
108                 .message.op = BOOTREQUEST,
109                 .message.htype = ARPHRD_ETHER,
110                 .message.hlen = ETHER_ADDR_LEN,
111                 .message.xid = htobe32(0x12345678),
112                 .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' },
113                 .option_type.code = DHCP_OPTION_MESSAGE_TYPE,
114                 .option_type.length = 1,
115                 .option_type.type = DHCP_DISCOVER,
116                 .end = DHCP_OPTION_END,
117         };
118         struct in_addr address_lo = {
119                 .s_addr = htonl(INADDR_LOOPBACK),
120         };
121
122         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
123         assert_se(sd_dhcp_server_set_address(server, &address_lo) >= 0);
124         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
125         assert_se(sd_dhcp_server_start(server) >= 0);
126
127         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
128         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 10) >= 0);
129         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
130
131         test.end = 0;
132         /* TODO, shouldn't this fail? */
133         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
134         test.end = DHCP_OPTION_END;
135         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
136
137         test.option_type.code = 0;
138         test.option_type.length = 0;
139         test.option_type.type = 0;
140         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
141         test.option_type.code = DHCP_OPTION_MESSAGE_TYPE;
142         test.option_type.length = 1;
143         test.option_type.type = DHCP_DISCOVER;
144         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
145
146         test.message.op = 0;
147         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
148         test.message.op = BOOTREQUEST;
149         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
150
151         test.message.htype = 0;
152         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
153         test.message.htype = ARPHRD_ETHER;
154         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
155
156         test.message.hlen = 0;
157         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
158         test.message.hlen = ETHER_ADDR_LEN;
159         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
160
161         test.option_type.type = DHCP_REQUEST;
162         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
163         test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS;
164         test.option_requested_ip.length = 4;
165         test.option_requested_ip.address = htobe32(0x12345678);
166         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_NAK);
167         test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER;
168         test.option_server_id.length = 4;
169         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
170         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
171         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
172
173         test.option_server_id.address = htobe32(0x12345678);
174         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
175         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
176         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
177         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 4);
178         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
179         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
180         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
181
182         test.option_client_id.code = DHCP_OPTION_CLIENT_IDENTIFIER;
183         test.option_client_id.length = 7;
184         test.option_client_id.id[0] = 0x01;
185         test.option_client_id.id[1] = 'A';
186         test.option_client_id.id[2] = 'B';
187         test.option_client_id.id[3] = 'C';
188         test.option_client_id.id[4] = 'D';
189         test.option_client_id.id[5] = 'E';
190         test.option_client_id.id[6] = 'F';
191         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
192
193         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
194         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
195 }
196
197 static void test_client_id_hash(void) {
198         DHCPClientId a = {
199                 .length = 4,
200         }, b = {
201                 .length = 4,
202         };
203         uint8_t hash_key[HASH_KEY_SIZE] = {
204                 '0', '1', '2', '3', '4', '5', '6', '7',
205                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
206         };
207
208         a.data = (uint8_t*)strdup("abcd");
209         b.data = (uint8_t*)strdup("abcd");
210
211         assert_se(client_id_compare_func(&a, &b) == 0);
212         assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
213         a.length = 3;
214         assert_se(client_id_compare_func(&a, &b) != 0);
215         a.length = 4;
216         assert_se(client_id_compare_func(&a, &b) == 0);
217         assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
218
219         b.length = 3;
220         assert_se(client_id_compare_func(&a, &b) != 0);
221         b.length = 4;
222         assert_se(client_id_compare_func(&a, &b) == 0);
223         assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
224
225         free(b.data);
226         b.data = (uint8_t*)strdup("abce");
227         assert_se(client_id_compare_func(&a, &b) != 0);
228
229         free(a.data);
230         free(b.data);
231 }
232
233 int main(int argc, char *argv[]) {
234         _cleanup_event_unref_ sd_event *e;
235         int r;
236
237         log_set_max_level(LOG_DEBUG);
238         log_parse_environment();
239         log_open();
240
241         assert_se(sd_event_new(&e) >= 0);
242
243         r = test_basic(e);
244         if (r != 0)
245                 return r;
246
247         test_message_handler();
248         test_client_id_hash();
249
250         return 0;
251 }