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