]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-dhcp-option.c
dhcp: export routes as opaque objects
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-option.c
CommitLineData
9116b406 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a0ae95c9 2
a0ae95c9 3#include <errno.h>
cf0fbc49
TA
4#include <stdbool.h>
5#include <stdio.h>
a0ae95c9 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
f693e9b3
TG
78 assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
79 assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
a0ae95c9
PF
80}
81
9116b406 82static void test_message_init(void) {
d47e1de4 83 _cleanup_free_ DHCPMessage *message = NULL;
2688ef60 84 size_t optlen = 4, optoffset;
d47e1de4 85 size_t len = sizeof(DHCPMessage) + optlen;
20b958bf 86 uint8_t *magic;
a0ae95c9
PF
87
88 message = malloc0(len);
89
d47e1de4 90 assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
76253e73 91 DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
d47e1de4
TG
92
93 assert_se(message->xid == htobe32(0x12345678));
94 assert_se(message->op == BOOTREQUEST);
a0ae95c9 95
d47e1de4 96 magic = (uint8_t*)&message->magic;
a0ae95c9 97
d47e1de4 98 assert_se(magic[0] == 99);
86be3e1e
TA
99 assert_se(magic[1] == 130);
100 assert_se(magic[2] == 83);
101 assert_se(magic[3] == 99);
d47e1de4 102
f693e9b3 103 assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
a10c375e
PF
104}
105
106static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
107 uint8_t *file, uint8_t filelen,
9116b406 108 uint8_t *sname, uint8_t snamelen) {
a10c375e 109 DHCPMessage *message;
d47e1de4 110 size_t len = sizeof(DHCPMessage) + optlen;
a0ae95c9 111
a10c375e 112 message = malloc0(len);
6f428772 113 assert_se(message);
a10c375e 114
a10c375e 115 if (options && optlen)
20b958bf 116 memcpy(&message->options, options, optlen);
a10c375e
PF
117
118 if (file && filelen <= 128)
119 memcpy(&message->file, file, filelen);
120
121 if (sname && snamelen <= 64)
122 memcpy(&message->sname, sname, snamelen);
123
124 return message;
125}
126
9116b406 127static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
0915fda6
ZJS
128 assert(*descpos >= 0);
129
a10c375e
PF
130 while (*descpos < *desclen) {
131 switch(descoption[*descpos]) {
132 case DHCP_OPTION_PAD:
133 *descpos += 1;
134 break;
135
136 case DHCP_OPTION_MESSAGE_TYPE:
137 case DHCP_OPTION_OVERLOAD:
138 *descpos += 3;
139 break;
140
141 default:
142 return;
143 }
144 }
145}
146
e4735228 147static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *userdata) {
89ca10c6 148 struct option_desc *desc = userdata;
a10c375e
PF
149 uint8_t *descoption = NULL;
150 int *desclen = NULL, *descpos = NULL;
151 uint8_t optcode = 0;
152 uint8_t optlen = 0;
153 uint8_t i;
154
12e0f830 155 assert_se((!desc && !code && !len) || desc);
a10c375e
PF
156
157 if (!desc)
158 return -EINVAL;
159
12e0f830
TG
160 assert_se(code != DHCP_OPTION_PAD);
161 assert_se(code != DHCP_OPTION_END);
162 assert_se(code != DHCP_OPTION_MESSAGE_TYPE);
163 assert_se(code != DHCP_OPTION_OVERLOAD);
a10c375e
PF
164
165 while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
166
167 if (desc->pos >= 0) {
168 descoption = &desc->options[0];
169 desclen = &desc->len;
170 descpos = &desc->pos;
171 } else if (desc->filepos >= 0) {
172 descoption = &desc->file[0];
173 desclen = &desc->filelen;
174 descpos = &desc->filepos;
175 } else if (desc->snamepos >= 0) {
176 descoption = &desc->sname[0];
177 desclen = &desc->snamelen;
178 descpos = &desc->snamepos;
179 }
180
12e0f830 181 assert_se(descoption && desclen && descpos);
a10c375e
PF
182
183 if (*desclen)
184 test_ignore_opts(descoption, descpos, desclen);
185
186 if (*descpos < *desclen)
187 break;
188
189 if (*descpos == *desclen)
190 *descpos = -1;
191 }
192
12e0f830
TG
193 assert_se(descpos);
194 assert_se(*descpos != -1);
a10c375e
PF
195
196 optcode = descoption[*descpos];
197 optlen = descoption[*descpos + 1];
198
199 if (verbose)
200 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
201 len, optlen);
202
12e0f830
TG
203 assert_se(code == optcode);
204 assert_se(len == optlen);
a10c375e
PF
205
206 for (i = 0; i < len; i++) {
207
208 if (verbose)
e4735228 209 printf("0x%02x(0x%02x) ", ((uint8_t*) option)[i],
a10c375e
PF
210 descoption[*descpos + 2 + i]);
211
e4735228 212 assert_se(((uint8_t*) option)[i] == descoption[*descpos + 2 + i]);
a10c375e
PF
213 }
214
215 if (verbose)
216 printf("\n");
217
218 *descpos += optlen + 2;
219
220 test_ignore_opts(descoption, descpos, desclen);
221
222 if (desc->pos != -1 && desc->pos == desc->len)
223 desc->pos = -1;
224
225 if (desc->filepos != -1 && desc->filepos == desc->filelen)
226 desc->filepos = -1;
227
228 if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
229 desc->snamepos = -1;
230
231 return 0;
232}
233
9116b406 234static void test_options(struct option_desc *desc) {
a10c375e
PF
235 uint8_t *options = NULL;
236 uint8_t *file = NULL;
237 uint8_t *sname = NULL;
238 int optlen = 0;
239 int filelen = 0;
240 int snamelen = 0;
241 int buflen = 0;
d47e1de4 242 _cleanup_free_ DHCPMessage *message = NULL;
a10c375e
PF
243 int res;
244
245 if (desc) {
246 file = &desc->file[0];
247 filelen = desc->filelen;
248 if (!filelen)
249 desc->filepos = -1;
250
251 sname = &desc->sname[0];
252 snamelen = desc->snamelen;
253 if (!snamelen)
254 desc->snamepos = -1;
255
256 options = &desc->options[0];
257 optlen = desc->len;
258 desc->pos = 0;
259 }
260 message = create_message(options, optlen, file, filelen,
d47e1de4 261 sname, snamelen);
a10c375e 262
d47e1de4 263 buflen = sizeof(DHCPMessage) + optlen;
a10c375e
PF
264
265 if (!desc) {
f693e9b3 266 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
a10c375e 267 } else if (desc->success) {
f693e9b3
TG
268 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
269 assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
a10c375e 270 } else
f693e9b3 271 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
a10c375e
PF
272
273 if (verbose)
274 printf("DHCP type %s\n", dhcp_type(res));
a0ae95c9
PF
275}
276
d8b61a1d
PF
277static uint8_t options[64] = {
278 'A', 'B', 'C', 'D',
279 160, 2, 0x11, 0x12,
280 0,
281 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
282 0,
283 55, 3, 0x51, 0x52, 0x53,
284 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
285 255
286};
287
9116b406 288static void test_option_set(void) {
4eb20caa 289 _cleanup_free_ DHCPMessage *result = NULL;
20b958bf
TG
290 size_t offset = 0, len, pos;
291 unsigned i;
d8b61a1d 292
04b28be1
TG
293 result = malloc0(sizeof(DHCPMessage) + 11);
294 assert_se(result);
295
296 result->options[0] = 'A';
297 result->options[1] = 'B';
298 result->options[2] = 'C';
299 result->options[3] = 'D';
300
301 assert_se(dhcp_option_append(result, 0, &offset, 0, DHCP_OPTION_PAD,
302 0, NULL) == -ENOBUFS);
20b958bf 303 assert_se(offset == 0);
d8b61a1d 304
20b958bf 305 offset = 4;
04b28be1
TG
306 assert_se(dhcp_option_append(result, 5, &offset, 0, DHCP_OPTION_PAD,
307 0, NULL) == -ENOBUFS);
308 assert_se(offset == 4);
309 assert_se(dhcp_option_append(result, 6, &offset, 0, DHCP_OPTION_PAD,
310 0, NULL) >= 0);
20b958bf 311 assert_se(offset == 5);
d8b61a1d 312
20b958bf 313 offset = pos = 4;
04b28be1
TG
314 len = 11;
315 while (pos < len && options[pos] != DHCP_OPTION_END) {
316 assert_se(dhcp_option_append(result, len, &offset, DHCP_OVERLOAD_SNAME,
20b958bf
TG
317 options[pos],
318 options[pos + 1],
319 &options[pos + 2]) >= 0);
d8b61a1d 320
20b958bf 321 if (options[pos] == DHCP_OPTION_PAD)
d8b61a1d 322 pos++;
20b958bf 323 else
d8b61a1d 324 pos += 2 + options[pos + 1];
20b958bf 325
04b28be1
TG
326 if (pos < len)
327 assert_se(offset == pos);
d8b61a1d
PF
328 }
329
04b28be1 330 for (i = 0; i < 9; i++) {
d8b61a1d 331 if (verbose)
c4ef0548 332 printf("%2u: 0x%02x(0x%02x) (options)\n", i, result->options[i],
d8b61a1d 333 options[i]);
04b28be1
TG
334 assert_se(result->options[i] == options[i]);
335 }
336
337 if (verbose)
338 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result->options[9],
339 DHCP_OPTION_END);
340
341 assert_se(result->options[9] == DHCP_OPTION_END);
342
343 if (verbose)
344 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result->options[10],
345 DHCP_OPTION_PAD);
346
347 assert_se(result->options[10] == DHCP_OPTION_PAD);
348
349 for (i = 0; i < pos - 8; i++) {
350 if (verbose)
c4ef0548 351 printf("%2u: 0x%02x(0x%02x) (sname)\n", i, result->sname[i],
04b28be1
TG
352 options[i + 9]);
353 assert_se(result->sname[i] == options[i + 9]);
d8b61a1d
PF
354 }
355
356 if (verbose)
357 printf ("\n");
358}
359
9116b406
ZJS
360int main(int argc, char *argv[]) {
361 unsigned i;
a10c375e 362
a0ae95c9 363 test_invalid_buffer_length();
d47e1de4 364 test_message_init();
a0ae95c9 365
a10c375e
PF
366 test_options(NULL);
367
368 for (i = 0; i < ELEMENTSOF(option_tests); i++)
369 test_options(&option_tests[i]);
370
d8b61a1d
PF
371 test_option_set();
372
a0ae95c9
PF
373 return 0;
374}