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