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