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