]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-server.c
Merge pull request #6199 from poettering/systemctl-quiet
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-server.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5 Copyright (C) 2014 Tom Gundersen
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22
23 #include "sd-dhcp-server.h"
24 #include "sd-event.h"
25
26 #include "dhcp-server-internal.h"
27
28 static void test_pool(struct in_addr *address, unsigned size, int ret) {
29 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
30
31 assert_se(sd_dhcp_server_new(&server, 1) >= 0);
32
33 assert_se(sd_dhcp_server_configure_pool(server, address, 8, 0, size) == ret);
34 }
35
36 static int test_basic(sd_event *event) {
37 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
38 struct in_addr address_lo = {
39 .s_addr = htonl(INADDR_LOOPBACK),
40 };
41 struct in_addr address_any = {
42 .s_addr = htonl(INADDR_ANY),
43 };
44 int r;
45
46 /* attach to loopback interface */
47 assert_se(sd_dhcp_server_new(&server, 1) >= 0);
48 assert_se(server);
49
50 assert_se(sd_dhcp_server_attach_event(server, event, 0) >= 0);
51 assert_se(sd_dhcp_server_attach_event(server, event, 0) == -EBUSY);
52 assert_se(sd_dhcp_server_get_event(server) == event);
53 assert_se(sd_dhcp_server_detach_event(server) >= 0);
54 assert_se(!sd_dhcp_server_get_event(server));
55 assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
56 assert_se(sd_dhcp_server_attach_event(server, NULL, 0) == -EBUSY);
57
58 assert_se(sd_dhcp_server_ref(server) == server);
59 assert_se(!sd_dhcp_server_unref(server));
60
61 assert_se(sd_dhcp_server_start(server) == -EUNATCH);
62
63 assert_se(sd_dhcp_server_configure_pool(server, &address_any, 28, 0, 0) == -EINVAL);
64 assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 38, 0, 0) == -ERANGE);
65 assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0);
66 assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0);
67
68 test_pool(&address_any, 1, -EINVAL);
69 test_pool(&address_lo, 1, 0);
70
71 r = sd_dhcp_server_start(server);
72
73 if (r == -EPERM)
74 return EXIT_TEST_SKIP;
75 assert_se(r >= 0);
76
77 assert_se(sd_dhcp_server_start(server) == -EBUSY);
78 assert_se(sd_dhcp_server_stop(server) >= 0);
79 assert_se(sd_dhcp_server_stop(server) >= 0);
80 assert_se(sd_dhcp_server_start(server) >= 0);
81
82 return 0;
83 }
84
85 static void test_message_handler(void) {
86 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
87 struct {
88 DHCPMessage message;
89 struct {
90 uint8_t code;
91 uint8_t length;
92 uint8_t type;
93 } _packed_ option_type;
94 struct {
95 uint8_t code;
96 uint8_t length;
97 be32_t address;
98 } _packed_ option_requested_ip;
99 struct {
100 uint8_t code;
101 uint8_t length;
102 be32_t address;
103 } _packed_ option_server_id;
104 struct {
105 uint8_t code;
106 uint8_t length;
107 uint8_t id[7];
108 } _packed_ option_client_id;
109 uint8_t end;
110 } _packed_ test = {
111 .message.op = BOOTREQUEST,
112 .message.htype = ARPHRD_ETHER,
113 .message.hlen = ETHER_ADDR_LEN,
114 .message.xid = htobe32(0x12345678),
115 .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' },
116 .option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE,
117 .option_type.length = 1,
118 .option_type.type = DHCP_DISCOVER,
119 .end = SD_DHCP_OPTION_END,
120 };
121 struct in_addr address_lo = {
122 .s_addr = htonl(INADDR_LOOPBACK),
123 };
124
125 assert_se(sd_dhcp_server_new(&server, 1) >= 0);
126 assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0);
127 assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
128 assert_se(sd_dhcp_server_start(server) >= 0);
129
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 = SD_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 = SD_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 = SD_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 = SD_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 = SD_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 uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
199 struct siphash state;
200
201 siphash24_init(&state, key);
202 client_id_hash_func(id, &state);
203
204 return htole64(siphash24_finalize(&state));
205 }
206
207 static void test_client_id_hash(void) {
208 DHCPClientId a = {
209 .length = 4,
210 }, b = {
211 .length = 4,
212 };
213 uint8_t hash_key[HASH_KEY_SIZE] = {
214 '0', '1', '2', '3', '4', '5', '6', '7',
215 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
216 };
217
218 a.data = (uint8_t*)strdup("abcd");
219 b.data = (uint8_t*)strdup("abcd");
220
221 assert_se(client_id_compare_func(&a, &b) == 0);
222 assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
223 a.length = 3;
224 assert_se(client_id_compare_func(&a, &b) != 0);
225 a.length = 4;
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
229 b.length = 3;
230 assert_se(client_id_compare_func(&a, &b) != 0);
231 b.length = 4;
232 assert_se(client_id_compare_func(&a, &b) == 0);
233 assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
234
235 free(b.data);
236 b.data = (uint8_t*)strdup("abce");
237 assert_se(client_id_compare_func(&a, &b) != 0);
238
239 free(a.data);
240 free(b.data);
241 }
242
243 int main(int argc, char *argv[]) {
244 _cleanup_(sd_event_unrefp) sd_event *e;
245 int r;
246
247 log_set_max_level(LOG_DEBUG);
248 log_parse_environment();
249 log_open();
250
251 assert_se(sd_event_new(&e) >= 0);
252
253 r = test_basic(e);
254 if (r != 0)
255 return r;
256
257 test_message_handler();
258 test_client_id_hash();
259
260 return 0;
261 }