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