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