]>
Commit | Line | Data |
---|---|---|
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 | 15 | static 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 | 23 | static 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 | 72 | static 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 |
185 | static 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 |
194 | static 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 | 230 | int 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 | } |