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