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