]>
Commit | Line | Data |
---|---|---|
b44cd882 TG |
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 | ||
b44cd882 TG |
23 | #include <errno.h> |
24 | ||
25 | #include "sd-event.h" | |
26 | #include "event-util.h" | |
27 | ||
28 | #include "sd-dhcp-server.h" | |
29 | #include "dhcp-server-internal.h" | |
30 | ||
99634696 TG |
31 | static void test_pool(struct in_addr *address, unsigned size, int ret) { |
32 | _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; | |
33 | ||
34 | assert_se(sd_dhcp_server_new(&server, 1) >= 0); | |
35 | ||
36 | assert_se(sd_dhcp_server_configure_pool(server, address, 8, 0, size) == ret); | |
37 | } | |
38 | ||
6f08fb7b | 39 | static int test_basic(sd_event *event) { |
b44cd882 | 40 | _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; |
20af7091 TG |
41 | struct in_addr address_lo = { |
42 | .s_addr = htonl(INADDR_LOOPBACK), | |
43 | }; | |
44 | struct in_addr address_any = { | |
45 | .s_addr = htonl(INADDR_ANY), | |
46 | }; | |
6f08fb7b | 47 | int r; |
b44cd882 | 48 | |
3a864fe4 TG |
49 | /* attach to loopback interface */ |
50 | assert_se(sd_dhcp_server_new(&server, 1) >= 0); | |
b44cd882 TG |
51 | assert_se(server); |
52 | ||
53 | assert_se(sd_dhcp_server_attach_event(server, event, 0) >= 0); | |
54 | assert_se(sd_dhcp_server_attach_event(server, event, 0) == -EBUSY); | |
55 | assert_se(sd_dhcp_server_get_event(server) == event); | |
56 | assert_se(sd_dhcp_server_detach_event(server) >= 0); | |
57 | assert_se(!sd_dhcp_server_get_event(server)); | |
58 | assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0); | |
59 | assert_se(sd_dhcp_server_attach_event(server, NULL, 0) == -EBUSY); | |
60 | ||
61 | assert_se(sd_dhcp_server_ref(server) == server); | |
62 | assert_se(!sd_dhcp_server_unref(server)); | |
ff734080 | 63 | |
20af7091 | 64 | assert_se(sd_dhcp_server_start(server) == -EUNATCH); |
20af7091 | 65 | |
99634696 TG |
66 | assert_se(sd_dhcp_server_configure_pool(server, &address_any, 28, 0, 0) == -EINVAL); |
67 | assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 38, 0, 0) == -ERANGE); | |
68 | assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); | |
69 | assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) == -EBUSY); | |
70 | ||
71 | test_pool(&address_any, 1, -EINVAL); | |
72 | test_pool(&address_lo, 1, 0); | |
2dead812 | 73 | |
6f08fb7b TG |
74 | r = sd_dhcp_server_start(server); |
75 | ||
76 | if (r == -EPERM) | |
77 | return EXIT_TEST_SKIP; | |
78 | assert_se(r >= 0); | |
79 | ||
ff734080 TG |
80 | assert_se(sd_dhcp_server_start(server) == -EBUSY); |
81 | assert_se(sd_dhcp_server_stop(server) >= 0); | |
82 | assert_se(sd_dhcp_server_stop(server) >= 0); | |
83 | assert_se(sd_dhcp_server_start(server) >= 0); | |
6f08fb7b TG |
84 | |
85 | return 0; | |
b44cd882 TG |
86 | } |
87 | ||
be077570 TG |
88 | static void test_message_handler(void) { |
89 | _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; | |
90 | struct { | |
91 | DHCPMessage message; | |
92 | struct { | |
93 | uint8_t code; | |
94 | uint8_t length; | |
95 | uint8_t type; | |
96 | } _packed_ option_type; | |
2dead812 TG |
97 | struct { |
98 | uint8_t code; | |
99 | uint8_t length; | |
100 | be32_t address; | |
101 | } _packed_ option_requested_ip; | |
102 | struct { | |
103 | uint8_t code; | |
104 | uint8_t length; | |
105 | be32_t address; | |
106 | } _packed_ option_server_id; | |
87322b3a TG |
107 | struct { |
108 | uint8_t code; | |
109 | uint8_t length; | |
110 | uint8_t id[7]; | |
111 | } _packed_ option_client_id; | |
be077570 TG |
112 | uint8_t end; |
113 | } _packed_ test = { | |
114 | .message.op = BOOTREQUEST, | |
115 | .message.htype = ARPHRD_ETHER, | |
116 | .message.hlen = ETHER_ADDR_LEN, | |
2dead812 TG |
117 | .message.xid = htobe32(0x12345678), |
118 | .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' }, | |
be077570 TG |
119 | .option_type.code = DHCP_OPTION_MESSAGE_TYPE, |
120 | .option_type.length = 1, | |
121 | .option_type.type = DHCP_DISCOVER, | |
122 | .end = DHCP_OPTION_END, | |
123 | }; | |
20af7091 TG |
124 | struct in_addr address_lo = { |
125 | .s_addr = htonl(INADDR_LOOPBACK), | |
126 | }; | |
be077570 TG |
127 | |
128 | assert_se(sd_dhcp_server_new(&server, 1) >= 0); | |
99634696 | 129 | assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); |
20af7091 TG |
130 | assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0); |
131 | assert_se(sd_dhcp_server_start(server) >= 0); | |
be077570 | 132 | |
4dc35568 | 133 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
be077570 TG |
134 | |
135 | test.end = 0; | |
136 | /* TODO, shouldn't this fail? */ | |
4dc35568 | 137 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
be077570 | 138 | test.end = DHCP_OPTION_END; |
4dc35568 | 139 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
be077570 TG |
140 | |
141 | test.option_type.code = 0; | |
142 | test.option_type.length = 0; | |
143 | test.option_type.type = 0; | |
144 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
145 | test.option_type.code = DHCP_OPTION_MESSAGE_TYPE; | |
146 | test.option_type.length = 1; | |
147 | test.option_type.type = DHCP_DISCOVER; | |
4dc35568 | 148 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
be077570 TG |
149 | |
150 | test.message.op = 0; | |
151 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
152 | test.message.op = BOOTREQUEST; | |
4dc35568 | 153 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
be077570 TG |
154 | |
155 | test.message.htype = 0; | |
156 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
157 | test.message.htype = ARPHRD_ETHER; | |
4dc35568 | 158 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
be077570 TG |
159 | |
160 | test.message.hlen = 0; | |
161 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
162 | test.message.hlen = ETHER_ADDR_LEN; | |
4dc35568 | 163 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); |
2dead812 TG |
164 | |
165 | test.option_type.type = DHCP_REQUEST; | |
166 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
167 | test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS; | |
168 | test.option_requested_ip.length = 4; | |
169 | test.option_requested_ip.address = htobe32(0x12345678); | |
bd57b450 | 170 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_NAK); |
2dead812 TG |
171 | test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER; |
172 | test.option_server_id.length = 4; | |
173 | test.option_server_id.address = htobe32(INADDR_LOOPBACK); | |
174 | test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); | |
175 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK); | |
87322b3a | 176 | |
2dead812 TG |
177 | test.option_server_id.address = htobe32(0x12345678); |
178 | test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); | |
179 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
bd57b450 | 180 | test.option_server_id.address = htobe32(INADDR_LOOPBACK); |
87322b3a TG |
181 | test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 4); |
182 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); | |
183 | test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); | |
184 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK); | |
185 | ||
186 | test.option_client_id.code = DHCP_OPTION_CLIENT_IDENTIFIER; | |
187 | test.option_client_id.length = 7; | |
188 | test.option_client_id.id[0] = 0x01; | |
189 | test.option_client_id.id[1] = 'A'; | |
190 | test.option_client_id.id[2] = 'B'; | |
191 | test.option_client_id.id[3] = 'C'; | |
192 | test.option_client_id.id[4] = 'D'; | |
193 | test.option_client_id.id[5] = 'E'; | |
194 | test.option_client_id.id[6] = 'F'; | |
195 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK); | |
196 | ||
bd57b450 | 197 | test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30); |
2dead812 | 198 | assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); |
be077570 TG |
199 | } |
200 | ||
b826ab58 TG |
201 | static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) { |
202 | struct siphash state; | |
203 | ||
204 | siphash_init(&state, key); | |
205 | client_id_hash_func(id, &state); | |
206 | return siphash24_finalize(&state); | |
207 | } | |
208 | ||
87322b3a TG |
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); | |
b826ab58 | 224 | assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key)); |
87322b3a TG |
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); | |
b826ab58 | 229 | assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key)); |
87322b3a TG |
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); | |
b826ab58 | 235 | assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key)); |
87322b3a TG |
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 | ||
b44cd882 TG |
245 | int main(int argc, char *argv[]) { |
246 | _cleanup_event_unref_ sd_event *e; | |
6f08fb7b | 247 | int r; |
b44cd882 TG |
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 | ||
6f08fb7b TG |
255 | r = test_basic(e); |
256 | if (r != 0) | |
257 | return r; | |
258 | ||
be077570 | 259 | test_message_handler(); |
87322b3a | 260 | test_client_id_hash(); |
b44cd882 TG |
261 | |
262 | return 0; | |
263 | } |