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