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