]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-dhcp-option.c
Merge pull request #16223 from cgzones/user_selinux
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-option.c
CommitLineData
ddb82ec2
LP
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
a0ae95c9 3#include <errno.h>
ddb82ec2 4#include <net/if_arp.h>
cf0fbc49
TA
5#include <stdbool.h>
6#include <stdio.h>
a0ae95c9 7#include <string.h>
a0ae95c9 8
b5efdb8a 9#include "alloc-util.h"
a0ae95c9 10#include "dhcp-internal.h"
b5efdb8a
LP
11#include "dhcp-protocol.h"
12#include "macro.h"
0a970718 13#include "memory-util.h"
a0ae95c9 14
a10c375e
PF
15struct option_desc {
16 uint8_t sname[64];
17 int snamelen;
18 uint8_t file[128];
19 int filelen;
20 uint8_t options[128];
21 int len;
22 bool success;
23 int filepos;
24 int snamepos;
25 int pos;
26};
27
28static bool verbose = false;
29
30static struct option_desc option_tests[] = {
31 { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
32 { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
22805d92 33 SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, },
a10c375e
PF
34 { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
35 { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
36 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
37 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
38 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
39 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
40 40, true, },
22805d92 41 { {}, 0, {}, 0, { SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER,
a10c375e
PF
42 42, 3, 0, 0, 0 }, 8, true, },
43 { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
44
45 { {}, 0,
22805d92
BG
46 { 222, 3, 1, 2, 3, SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
47 { SD_DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
a10c375e 48
22805d92 49 { { 1, 4, 1, 2, 3, 4, SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9,
a10c375e 50 { 222, 3, 1, 2, 3 }, 5,
22805d92 51 { SD_DHCP_OPTION_OVERLOAD, 1,
a10c375e
PF
52 DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
53};
54
9116b406 55static const char *dhcp_type(int type) {
a10c375e
PF
56 switch(type) {
57 case DHCP_DISCOVER:
58 return "DHCPDISCOVER";
59 case DHCP_OFFER:
60 return "DHCPOFFER";
61 case DHCP_REQUEST:
62 return "DHCPREQUEST";
63 case DHCP_DECLINE:
64 return "DHCPDECLINE";
65 case DHCP_ACK:
66 return "DHCPACK";
67 case DHCP_NAK:
68 return "DHCPNAK";
69 case DHCP_RELEASE:
70 return "DHCPRELEASE";
71 default:
72 return "unknown";
73 }
74}
75
9116b406 76static void test_invalid_buffer_length(void) {
a0ae95c9
PF
77 DHCPMessage message;
78
f693e9b3
TG
79 assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
80 assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
a0ae95c9
PF
81}
82
9116b406 83static void test_message_init(void) {
d47e1de4 84 _cleanup_free_ DHCPMessage *message = NULL;
2688ef60 85 size_t optlen = 4, optoffset;
d47e1de4 86 size_t len = sizeof(DHCPMessage) + optlen;
20b958bf 87 uint8_t *magic;
a0ae95c9
PF
88
89 message = malloc0(len);
90
d47e1de4 91 assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
76253e73 92 DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
d47e1de4
TG
93
94 assert_se(message->xid == htobe32(0x12345678));
95 assert_se(message->op == BOOTREQUEST);
a0ae95c9 96
d47e1de4 97 magic = (uint8_t*)&message->magic;
a0ae95c9 98
d47e1de4 99 assert_se(magic[0] == 99);
86be3e1e
TA
100 assert_se(magic[1] == 130);
101 assert_se(magic[2] == 83);
102 assert_se(magic[3] == 99);
d47e1de4 103
f693e9b3 104 assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
a10c375e
PF
105}
106
107static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
108 uint8_t *file, uint8_t filelen,
9116b406 109 uint8_t *sname, uint8_t snamelen) {
a10c375e 110 DHCPMessage *message;
d47e1de4 111 size_t len = sizeof(DHCPMessage) + optlen;
a0ae95c9 112
a10c375e 113 message = malloc0(len);
6f428772 114 assert_se(message);
a10c375e 115
75f32f04
ZJS
116 memcpy_safe(&message->options, options, optlen);
117 memcpy_safe(&message->file, file, filelen);
118 memcpy_safe(&message->sname, sname, snamelen);
a10c375e
PF
119
120 return message;
121}
122
9116b406 123static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
0915fda6
ZJS
124 assert(*descpos >= 0);
125
a10c375e
PF
126 while (*descpos < *desclen) {
127 switch(descoption[*descpos]) {
22805d92 128 case SD_DHCP_OPTION_PAD:
a10c375e
PF
129 *descpos += 1;
130 break;
131
22805d92
BG
132 case SD_DHCP_OPTION_MESSAGE_TYPE:
133 case SD_DHCP_OPTION_OVERLOAD:
a10c375e
PF
134 *descpos += 3;
135 break;
136
137 default:
138 return;
139 }
140 }
141}
142
e4735228 143static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *userdata) {
89ca10c6 144 struct option_desc *desc = userdata;
a10c375e
PF
145 uint8_t *descoption = NULL;
146 int *desclen = NULL, *descpos = NULL;
147 uint8_t optcode = 0;
148 uint8_t optlen = 0;
149 uint8_t i;
150
12e0f830 151 assert_se((!desc && !code && !len) || desc);
a10c375e
PF
152
153 if (!desc)
154 return -EINVAL;
155
22805d92
BG
156 assert_se(code != SD_DHCP_OPTION_PAD);
157 assert_se(code != SD_DHCP_OPTION_END);
158 assert_se(code != SD_DHCP_OPTION_MESSAGE_TYPE);
159 assert_se(code != SD_DHCP_OPTION_OVERLOAD);
a10c375e
PF
160
161 while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
162
163 if (desc->pos >= 0) {
164 descoption = &desc->options[0];
165 desclen = &desc->len;
166 descpos = &desc->pos;
167 } else if (desc->filepos >= 0) {
168 descoption = &desc->file[0];
169 desclen = &desc->filelen;
170 descpos = &desc->filepos;
171 } else if (desc->snamepos >= 0) {
172 descoption = &desc->sname[0];
173 desclen = &desc->snamelen;
174 descpos = &desc->snamepos;
175 }
176
12e0f830 177 assert_se(descoption && desclen && descpos);
a10c375e
PF
178
179 if (*desclen)
180 test_ignore_opts(descoption, descpos, desclen);
181
182 if (*descpos < *desclen)
183 break;
184
185 if (*descpos == *desclen)
186 *descpos = -1;
187 }
188
12e0f830
TG
189 assert_se(descpos);
190 assert_se(*descpos != -1);
a10c375e
PF
191
192 optcode = descoption[*descpos];
193 optlen = descoption[*descpos + 1];
194
195 if (verbose)
196 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
197 len, optlen);
198
12e0f830
TG
199 assert_se(code == optcode);
200 assert_se(len == optlen);
a10c375e
PF
201
202 for (i = 0; i < len; i++) {
203
204 if (verbose)
e4735228 205 printf("0x%02x(0x%02x) ", ((uint8_t*) option)[i],
a10c375e
PF
206 descoption[*descpos + 2 + i]);
207
e4735228 208 assert_se(((uint8_t*) option)[i] == descoption[*descpos + 2 + i]);
a10c375e
PF
209 }
210
211 if (verbose)
212 printf("\n");
213
214 *descpos += optlen + 2;
215
216 test_ignore_opts(descoption, descpos, desclen);
217
218 if (desc->pos != -1 && desc->pos == desc->len)
219 desc->pos = -1;
220
221 if (desc->filepos != -1 && desc->filepos == desc->filelen)
222 desc->filepos = -1;
223
224 if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
225 desc->snamepos = -1;
226
227 return 0;
228}
229
9116b406 230static void test_options(struct option_desc *desc) {
a10c375e
PF
231 uint8_t *options = NULL;
232 uint8_t *file = NULL;
233 uint8_t *sname = NULL;
234 int optlen = 0;
235 int filelen = 0;
236 int snamelen = 0;
237 int buflen = 0;
d47e1de4 238 _cleanup_free_ DHCPMessage *message = NULL;
a10c375e
PF
239 int res;
240
241 if (desc) {
242 file = &desc->file[0];
243 filelen = desc->filelen;
244 if (!filelen)
245 desc->filepos = -1;
246
247 sname = &desc->sname[0];
248 snamelen = desc->snamelen;
249 if (!snamelen)
250 desc->snamepos = -1;
251
252 options = &desc->options[0];
253 optlen = desc->len;
254 desc->pos = 0;
255 }
256 message = create_message(options, optlen, file, filelen,
d47e1de4 257 sname, snamelen);
a10c375e 258
d47e1de4 259 buflen = sizeof(DHCPMessage) + optlen;
a10c375e
PF
260
261 if (!desc) {
f693e9b3 262 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
a10c375e 263 } else if (desc->success) {
f693e9b3
TG
264 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
265 assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
a10c375e 266 } else
f693e9b3 267 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
a10c375e
PF
268
269 if (verbose)
270 printf("DHCP type %s\n", dhcp_type(res));
a0ae95c9
PF
271}
272
d8b61a1d
PF
273static uint8_t options[64] = {
274 'A', 'B', 'C', 'D',
275 160, 2, 0x11, 0x12,
276 0,
277 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
278 0,
279 55, 3, 0x51, 0x52, 0x53,
280 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
281 255
282};
283
9116b406 284static void test_option_set(void) {
4eb20caa 285 _cleanup_free_ DHCPMessage *result = NULL;
20b958bf
TG
286 size_t offset = 0, len, pos;
287 unsigned i;
d8b61a1d 288
04b28be1
TG
289 result = malloc0(sizeof(DHCPMessage) + 11);
290 assert_se(result);
291
292 result->options[0] = 'A';
293 result->options[1] = 'B';
294 result->options[2] = 'C';
295 result->options[3] = 'D';
296
22805d92 297 assert_se(dhcp_option_append(result, 0, &offset, 0, SD_DHCP_OPTION_PAD,
04b28be1 298 0, NULL) == -ENOBUFS);
20b958bf 299 assert_se(offset == 0);
d8b61a1d 300
20b958bf 301 offset = 4;
22805d92 302 assert_se(dhcp_option_append(result, 5, &offset, 0, SD_DHCP_OPTION_PAD,
04b28be1
TG
303 0, NULL) == -ENOBUFS);
304 assert_se(offset == 4);
22805d92 305 assert_se(dhcp_option_append(result, 6, &offset, 0, SD_DHCP_OPTION_PAD,
04b28be1 306 0, NULL) >= 0);
20b958bf 307 assert_se(offset == 5);
d8b61a1d 308
20b958bf 309 offset = pos = 4;
04b28be1 310 len = 11;
22805d92 311 while (pos < len && options[pos] != SD_DHCP_OPTION_END) {
04b28be1 312 assert_se(dhcp_option_append(result, len, &offset, DHCP_OVERLOAD_SNAME,
20b958bf
TG
313 options[pos],
314 options[pos + 1],
315 &options[pos + 2]) >= 0);
d8b61a1d 316
22805d92 317 if (options[pos] == SD_DHCP_OPTION_PAD)
d8b61a1d 318 pos++;
20b958bf 319 else
d8b61a1d 320 pos += 2 + options[pos + 1];
20b958bf 321
04b28be1
TG
322 if (pos < len)
323 assert_se(offset == pos);
d8b61a1d
PF
324 }
325
04b28be1 326 for (i = 0; i < 9; i++) {
d8b61a1d 327 if (verbose)
c4ef0548 328 printf("%2u: 0x%02x(0x%02x) (options)\n", i, result->options[i],
d8b61a1d 329 options[i]);
04b28be1
TG
330 assert_se(result->options[i] == options[i]);
331 }
332
333 if (verbose)
334 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result->options[9],
22805d92 335 SD_DHCP_OPTION_END);
04b28be1 336
22805d92 337 assert_se(result->options[9] == SD_DHCP_OPTION_END);
04b28be1
TG
338
339 if (verbose)
340 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result->options[10],
22805d92 341 SD_DHCP_OPTION_PAD);
04b28be1 342
22805d92 343 assert_se(result->options[10] == SD_DHCP_OPTION_PAD);
04b28be1
TG
344
345 for (i = 0; i < pos - 8; i++) {
346 if (verbose)
c4ef0548 347 printf("%2u: 0x%02x(0x%02x) (sname)\n", i, result->sname[i],
04b28be1
TG
348 options[i + 9]);
349 assert_se(result->sname[i] == options[i + 9]);
d8b61a1d
PF
350 }
351
352 if (verbose)
353 printf ("\n");
354}
355
9116b406
ZJS
356int main(int argc, char *argv[]) {
357 unsigned i;
a10c375e 358
a0ae95c9 359 test_invalid_buffer_length();
d47e1de4 360 test_message_init();
a0ae95c9 361
a10c375e
PF
362 test_options(NULL);
363
364 for (i = 0; i < ELEMENTSOF(option_tests); i++)
365 test_options(&option_tests[i]);
366
d8b61a1d
PF
367 test_option_set();
368
a0ae95c9
PF
369 return 0;
370}