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