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