chiark / gitweb /
install: make InstallContext::{will_install,have_installed} OrderedHashmaps
[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, 28) == -EINVAL);
60         assert_se(sd_dhcp_server_set_address(server, &address_lo, 38) == -ERANGE);
61         assert_se(sd_dhcp_server_set_address(server, &address_lo, 8) >= 0);
62         assert_se(sd_dhcp_server_set_address(server, &address_lo, 8) == -EBUSY);
63
64         assert_se(sd_dhcp_server_set_lease_pool(server, &address_any, 1) == -EINVAL);
65         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 0) == -EINVAL);
66         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) >= 0);
67         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) == -EBUSY);
68
69         r = sd_dhcp_server_start(server);
70
71         if (r == -EPERM)
72                 return EXIT_TEST_SKIP;
73         assert_se(r >= 0);
74
75         assert_se(sd_dhcp_server_start(server) == -EBUSY);
76         assert_se(sd_dhcp_server_stop(server) >= 0);
77         assert_se(sd_dhcp_server_stop(server) >= 0);
78         assert_se(sd_dhcp_server_start(server) >= 0);
79
80         return 0;
81 }
82
83 static void test_message_handler(void) {
84         _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
85         struct {
86                 DHCPMessage message;
87                 struct {
88                         uint8_t code;
89                         uint8_t length;
90                         uint8_t type;
91                 } _packed_ option_type;
92                 struct {
93                         uint8_t code;
94                         uint8_t length;
95                         be32_t address;
96                 } _packed_ option_requested_ip;
97                 struct {
98                         uint8_t code;
99                         uint8_t length;
100                         be32_t address;
101                 } _packed_ option_server_id;
102                 struct {
103                         uint8_t code;
104                         uint8_t length;
105                         uint8_t id[7];
106                 } _packed_ option_client_id;
107                 uint8_t end;
108         } _packed_ test = {
109                 .message.op = BOOTREQUEST,
110                 .message.htype = ARPHRD_ETHER,
111                 .message.hlen = ETHER_ADDR_LEN,
112                 .message.xid = htobe32(0x12345678),
113                 .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' },
114                 .option_type.code = DHCP_OPTION_MESSAGE_TYPE,
115                 .option_type.length = 1,
116                 .option_type.type = DHCP_DISCOVER,
117                 .end = DHCP_OPTION_END,
118         };
119         struct in_addr address_lo = {
120                 .s_addr = htonl(INADDR_LOOPBACK),
121         };
122
123         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
124         assert_se(sd_dhcp_server_set_address(server, &address_lo, 8) >= 0);
125         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
126         assert_se(sd_dhcp_server_start(server) >= 0);
127
128         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
129         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 10) >= 0);
130         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
131
132         test.end = 0;
133         /* TODO, shouldn't this fail? */
134         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
135         test.end = DHCP_OPTION_END;
136         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
137
138         test.option_type.code = 0;
139         test.option_type.length = 0;
140         test.option_type.type = 0;
141         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
142         test.option_type.code = DHCP_OPTION_MESSAGE_TYPE;
143         test.option_type.length = 1;
144         test.option_type.type = DHCP_DISCOVER;
145         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
146
147         test.message.op = 0;
148         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
149         test.message.op = BOOTREQUEST;
150         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
151
152         test.message.htype = 0;
153         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
154         test.message.htype = ARPHRD_ETHER;
155         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
156
157         test.message.hlen = 0;
158         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
159         test.message.hlen = ETHER_ADDR_LEN;
160         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
161
162         test.option_type.type = DHCP_REQUEST;
163         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
164         test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS;
165         test.option_requested_ip.length = 4;
166         test.option_requested_ip.address = htobe32(0x12345678);
167         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_NAK);
168         test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER;
169         test.option_server_id.length = 4;
170         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
171         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
172         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
173
174         test.option_server_id.address = htobe32(0x12345678);
175         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
176         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
177         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
178         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 4);
179         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
180         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
181         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
182
183         test.option_client_id.code = DHCP_OPTION_CLIENT_IDENTIFIER;
184         test.option_client_id.length = 7;
185         test.option_client_id.id[0] = 0x01;
186         test.option_client_id.id[1] = 'A';
187         test.option_client_id.id[2] = 'B';
188         test.option_client_id.id[3] = 'C';
189         test.option_client_id.id[4] = 'D';
190         test.option_client_id.id[5] = 'E';
191         test.option_client_id.id[6] = 'F';
192         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
193
194         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
195         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
196 }
197
198 static void test_client_id_hash(void) {
199         DHCPClientId a = {
200                 .length = 4,
201         }, b = {
202                 .length = 4,
203         };
204         uint8_t hash_key[HASH_KEY_SIZE] = {
205                 '0', '1', '2', '3', '4', '5', '6', '7',
206                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
207         };
208
209         a.data = (uint8_t*)strdup("abcd");
210         b.data = (uint8_t*)strdup("abcd");
211
212         assert_se(client_id_compare_func(&a, &b) == 0);
213         assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
214         a.length = 3;
215         assert_se(client_id_compare_func(&a, &b) != 0);
216         a.length = 4;
217         assert_se(client_id_compare_func(&a, &b) == 0);
218         assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
219
220         b.length = 3;
221         assert_se(client_id_compare_func(&a, &b) != 0);
222         b.length = 4;
223         assert_se(client_id_compare_func(&a, &b) == 0);
224         assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
225
226         free(b.data);
227         b.data = (uint8_t*)strdup("abce");
228         assert_se(client_id_compare_func(&a, &b) != 0);
229
230         free(a.data);
231         free(b.data);
232 }
233
234 int main(int argc, char *argv[]) {
235         _cleanup_event_unref_ sd_event *e;
236         int r;
237
238         log_set_max_level(LOG_DEBUG);
239         log_parse_environment();
240         log_open();
241
242         assert_se(sd_event_new(&e) >= 0);
243
244         r = test_basic(e);
245         if (r != 0)
246                 return r;
247
248         test_message_handler();
249         test_client_id_hash();
250
251         return 0;
252 }