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