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