1 /* $OpenBSD: options.c,v 1.35 2017/02/13 22:33:39 krw Exp $ */
2
3 /* DHCP options parsing and reassembly. */
4
5 /*
6 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43 #include <sys/types.h>
44 #include <sys/socket.h>
45
46 #include <net/if.h>
47
48 #include <netinet/in.h>
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "dhcp.h"
55 #include "tree.h"
56 #include "dhcpd.h"
57 #include "log.h"
58
59 int bad_options = 0;
60 int bad_options_max = 5;
61
62 void parse_options(struct packet *);
63 void parse_option_buffer(struct packet *, unsigned char *, int);
64 void create_priority_list(unsigned char *, unsigned char *, int);
65 int store_option_fragment(unsigned char *, int, unsigned char,
66 int, unsigned char *);
67 int store_options(unsigned char *, int, struct tree_cache **,
68 unsigned char *, int, int);
69
70
71 /*
72 * Parse all available options out of the specified packet.
73 */
74 void
parse_options(struct packet * packet)75 parse_options(struct packet *packet)
76 {
77 /* Initially, zero all option pointers. */
78 memset(packet->options, 0, sizeof(packet->options));
79
80 /* If we don't see the magic cookie, there's nothing to parse. */
81 if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) {
82 packet->options_valid = 0;
83 return;
84 }
85
86 /*
87 * Go through the options field, up to the end of the packet or
88 * the End field.
89 */
90 parse_option_buffer(packet, &packet->raw->options[4],
91 packet->packet_length - DHCP_FIXED_NON_UDP - 4);
92
93 /*
94 * If we parsed a DHCP Option Overload option, parse more
95 * options out of the buffer(s) containing them.
96 */
97 if (packet->options_valid &&
98 packet->options[DHO_DHCP_OPTION_OVERLOAD].data) {
99 if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)
100 parse_option_buffer(packet,
101 (unsigned char *)packet->raw->file,
102 sizeof(packet->raw->file));
103 if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)
104 parse_option_buffer(packet,
105 (unsigned char *)packet->raw->sname,
106 sizeof(packet->raw->sname));
107 }
108 }
109
110 /*
111 * Parse options out of the specified buffer, storing addresses of
112 * option values in packet->options and setting packet->options_valid if
113 * no errors are encountered.
114 */
115 void
parse_option_buffer(struct packet * packet,unsigned char * buffer,int length)116 parse_option_buffer(struct packet *packet,
117 unsigned char *buffer, int length)
118 {
119 unsigned char *s, *t;
120 unsigned char *end = buffer + length;
121 int len;
122 int code;
123
124 for (s = buffer; *s != DHO_END && s < end; ) {
125 code = s[0];
126
127 /* Pad options don't have a length - just skip them. */
128 if (code == DHO_PAD) {
129 s++;
130 continue;
131 }
132 if (s + 2 > end) {
133 len = 65536;
134 goto bogus;
135 }
136
137 /*
138 * All other fields (except end, see above) have a
139 * one-byte length.
140 */
141 len = s[1];
142
143 /*
144 * If the length is outrageous, silently skip the rest,
145 * and mark the packet bad. Unfortunately some crappy
146 * dhcp servers always seem to give us garbage on the
147 * end of a packet. so rather than keep refusing, give
148 * up and try to take one after seeing a few without
149 * anything good.
150 */
151 if (s + len + 2 > end) {
152 bogus:
153 bad_options++;
154 log_warnx("option %s (%d) %s.",
155 dhcp_options[code].name, len,
156 "larger than buffer");
157 if (bad_options == bad_options_max) {
158 packet->options_valid = 1;
159 bad_options = 0;
160 log_warnx("Many bogus options seen in "
161 "offers.");
162 log_warnx("Taking this offer in spite of "
163 "bogus");
164 log_warnx("options - hope for the best!");
165 } else {
166 log_warnx("rejecting bogus offer.");
167 packet->options_valid = 0;
168 }
169 return;
170 }
171 /*
172 * If we haven't seen this option before, just make
173 * space for it and copy it there.
174 */
175 if (!packet->options[code].data) {
176 t = calloc(1, len + 1);
177 if (!t)
178 fatalx("Can't allocate storage for option %s.",
179 dhcp_options[code].name);
180 /*
181 * Copy and NUL-terminate the option (in case
182 * it's an ASCII string).
183 */
184 memcpy(t, &s[2], len);
185 t[len] = 0;
186 packet->options[code].len = len;
187 packet->options[code].data = t;
188 } else {
189 /*
190 * If it's a repeat, concatenate it to whatever
191 * we last saw. This is really only required
192 * for clients, but what the heck...
193 */
194 t = calloc(1, len + packet->options[code].len + 1);
195 if (!t)
196 fatalx("Can't expand storage for option %s.",
197 dhcp_options[code].name);
198 memcpy(t, packet->options[code].data,
199 packet->options[code].len);
200 memcpy(t + packet->options[code].len,
201 &s[2], len);
202 packet->options[code].len += len;
203 t[packet->options[code].len] = 0;
204 free(packet->options[code].data);
205 packet->options[code].data = t;
206 }
207 s += len + 2;
208 }
209 packet->options_valid = 1;
210 }
211
212 /*
213 * Fill priority_list with a complete list of DHCP options sorted by
214 * priority. i.e.
215 * 1) Mandatory options.
216 * 2) Options from prl that are not already present.
217 * 3) Options from the default list that are not already present.
218 */
219 void
create_priority_list(unsigned char * priority_list,unsigned char * prl,int prl_len)220 create_priority_list(unsigned char *priority_list, unsigned char *prl,
221 int prl_len)
222 {
223 unsigned char stored_list[256];
224 int i, priority_len = 0;
225
226 /* clear stored_list, priority_list should be cleared before */
227 memset(&stored_list, 0, sizeof(stored_list));
228
229 /* Some options we don't want on the priority list. */
230 stored_list[DHO_PAD] = 1;
231 stored_list[DHO_END] = 1;
232
233 /* Mandatory options. */
234 for(i = 0; dhcp_option_default_priority_list[i] != DHO_END; i++) {
235 priority_list[priority_len++] =
236 dhcp_option_default_priority_list[i];
237 stored_list[dhcp_option_default_priority_list[i]] = 1;
238 }
239
240 /* Supplied priority list. */
241 if (!prl)
242 prl_len = 0;
243 for(i = 0; i < prl_len; i++) {
244 /* CLASSLESS routes always have priority, sayeth RFC 3442. */
245 if (prl[i] == DHO_CLASSLESS_STATIC_ROUTES ||
246 prl[i] == DHO_CLASSLESS_MS_STATIC_ROUTES) {
247 priority_list[priority_len++] = prl[i];
248 stored_list[prl[i]] = 1;
249 }
250 }
251 for(i = 0; i < prl_len; i++) {
252 if (stored_list[prl[i]])
253 continue;
254 priority_list[priority_len++] = prl[i];
255 stored_list[prl[i]] = 1;
256 }
257
258 /* Default priority list. */
259 prl = dhcp_option_default_priority_list;
260 for(i = 0; i < 256; i++) {
261 if (stored_list[prl[i]])
262 continue;
263 priority_list[priority_len++] = prl[i];
264 stored_list[prl[i]] = 1;
265 }
266 }
267 /*
268 * cons options into a big buffer, and then split them out into the
269 * three separate buffers if needed. This allows us to cons up a set of
270 * vendor options using the same routine.
271 */
272 int
cons_options(struct packet * inpacket,struct dhcp_packet * outpacket,int mms,struct tree_cache ** options,int overload,int terminate,int bootpp,u_int8_t * prl,int prl_len)273 cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
274 int mms, struct tree_cache **options,
275 int overload, /* Overload flags that may be set. */
276 int terminate, int bootpp, u_int8_t *prl, int prl_len)
277 {
278 unsigned char priority_list[256];
279 unsigned char buffer[4096]; /* Really big buffer... */
280 int bufix, main_buffer_size, option_size;
281
282 /*
283 * If the client has provided a maximum DHCP message size, use
284 * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use
285 * up to the minimum IP MTU size (576 bytes).
286 *
287 * XXX if a BOOTP client specifies a max message size, we will
288 * honor it.
289 */
290 if (!mms &&
291 inpacket &&
292 inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data &&
293 (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].len >=
294 sizeof(u_int16_t))) {
295 mms = getUShort(
296 inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data);
297 }
298
299 if (mms) {
300 if (mms < 576)
301 mms = 576; /* mms must be >= minimum IP MTU */
302 main_buffer_size = mms - DHCP_FIXED_LEN;
303 } else if (bootpp)
304 main_buffer_size = 64;
305 else
306 main_buffer_size = 576 - DHCP_FIXED_LEN;
307
308 if (main_buffer_size > sizeof(outpacket->options))
309 main_buffer_size = sizeof(outpacket->options);
310
311 /*
312 * Initialize the available buffers, some or all of which may not be
313 * used.
314 */
315 memset(outpacket->options, DHO_PAD, sizeof(outpacket->options));
316 if (overload & 1)
317 memset(outpacket->file, DHO_PAD, DHCP_FILE_LEN);
318 if (overload & 2)
319 memset(outpacket->sname, DHO_PAD, DHCP_SNAME_LEN);
320 if (bootpp)
321 overload = 0; /* Don't use overload buffers for bootp! */
322
323 /*
324 * Get complete list of possible options in priority order. Use the
325 * list provided in the options. Lacking that use the list provided by
326 * prl. If that is not available just use the default list.
327 */
328 memset(&priority_list, 0, sizeof(priority_list));
329 if (inpacket &&
330 inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data)
331 create_priority_list(priority_list,
332 inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data,
333 inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].len);
334 else if (prl)
335 create_priority_list(priority_list, prl, prl_len);
336 else
337 create_priority_list(priority_list, NULL, 0);
338
339 /*
340 * Copy the options into the big buffer, including leading cookie and
341 * DHCP_OVERLOAD_OPTION, and DHO_END if it fits. All unused space will
342 * be set to DHO_PAD
343 */
344 option_size = store_options(buffer, main_buffer_size, options,
345 priority_list, overload, terminate);
346 if (option_size == 0)
347 return (DHCP_FIXED_NON_UDP);
348
349 /* Copy the main buffer. */
350 memcpy(&outpacket->options[0], buffer, main_buffer_size);
351 if (option_size <= main_buffer_size)
352 return (DHCP_FIXED_NON_UDP + option_size);
353
354 /* Copy the overflow buffers. */
355 bufix = main_buffer_size;
356 if (overload & 1) {
357 memcpy(outpacket->file, &buffer[bufix], DHCP_FILE_LEN);
358 bufix += DHCP_FILE_LEN;
359 }
360 if (overload & 2)
361 memcpy(outpacket->sname, &buffer[bufix], DHCP_SNAME_LEN);
362
363 return (DHCP_FIXED_NON_UDP + main_buffer_size);
364 }
365
366 /*
367 * Store a <code><length><data> fragment in buffer. Return the number of
368 * characters used. Return 0 if no data could be stored.
369 */
370 int
store_option_fragment(unsigned char * buffer,int buffer_size,unsigned char code,int length,unsigned char * data)371 store_option_fragment(unsigned char *buffer, int buffer_size,
372 unsigned char code, int length, unsigned char *data)
373 {
374 buffer_size -= 2; /* Space for option code and option length. */
375
376 if (buffer_size < 1)
377 return (0);
378
379 if (buffer_size > 255)
380 buffer_size = 255;
381 if (length > buffer_size)
382 length = buffer_size;
383
384 buffer[0] = code;
385 buffer[1] = length;
386
387 memcpy(&buffer[2], data, length);
388
389 return (length + 2);
390 }
391
392 /*
393 * Store all the requested options into the requested buffer. Insert the
394 * required cookie, DHO_DHCP_OPTION_OVERLOAD options and append a DHO_END if
395 * if fits. Ensure all buffer space is set to DHO_PAD if unused.
396 */
397 int
store_options(unsigned char * buffer,int main_buffer_size,struct tree_cache ** options,unsigned char * priority_list,int overload,int terminate)398 store_options(unsigned char *buffer, int main_buffer_size,
399 struct tree_cache **options, unsigned char *priority_list, int overload,
400 int terminate)
401 {
402 int buflen, code, cutoff, i, incr, ix, length, optstart, overflow;
403 int second_cutoff;
404 int bufix = 0;
405 int stored_classless = 0;
406
407 overload &= 3; /* Only consider valid bits. */
408
409 cutoff = main_buffer_size;
410 second_cutoff = cutoff + ((overload & 1) ? DHCP_FILE_LEN : 0);
411 buflen = second_cutoff + ((overload & 2) ? DHCP_SNAME_LEN : 0);
412
413 memset(buffer, DHO_PAD, buflen);
414 memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
415
416 if (overload)
417 bufix = 7; /* Reserve space for DHO_DHCP_OPTION_OVERLOAD. */
418 else
419 bufix = 4;
420
421 /*
422 * Store options in the order they appear in the priority list.
423 */
424 for (i = 0; i < 256; i++) {
425 /* Code for next option to try to store. */
426 code = priority_list[i];
427 if (code == DHO_PAD || code == DHO_END)
428 continue;
429
430 if (!options[code] || !tree_evaluate(options[code]))
431 continue;
432
433 /*
434 * RFC 3442 says:
435 *
436 * When a DHCP client requests the Classless Static
437 * Routes option and also requests either or both of the
438 * Router option and the Static Routes option, and the
439 * DHCP server is sending Classless Static Routes options
440 * to that client, the server SHOULD NOT include the
441 * Router or Static Routes options.
442 */
443 if ((code == DHO_ROUTERS || code == DHO_STATIC_ROUTES) &&
444 stored_classless)
445 continue;
446
447 /* We should now have a constant length for the option. */
448 length = options[code]->len;
449
450 /* Try to store the option. */
451 optstart = bufix;
452 ix = 0;
453 while (length) {
454 incr = store_option_fragment(&buffer[bufix],
455 cutoff - bufix, code, length,
456 options[code]->value + ix);
457
458 if (incr > 0) {
459 bufix += incr;
460 length -= incr - 2;
461 ix += incr - 2;
462 continue;
463 }
464
465 /*
466 * No fragment could be stored in the space before the
467 * cutoff. Fill the unusable space with DHO_PAD and
468 * move cutoff for another attempt.
469 */
470 memset(&buffer[bufix], DHO_PAD, cutoff - bufix);
471 bufix = cutoff;
472 if (cutoff < second_cutoff)
473 cutoff = second_cutoff;
474 else if (cutoff < buflen)
475 cutoff = buflen;
476 else
477 break;
478 }
479
480 if (length > 0) {
481 zapfrags:
482 memset(&buffer[optstart], DHO_PAD, buflen - optstart);
483 bufix = optstart;
484 } else if (terminate && dhcp_options[code].format[0] == 't') {
485 if (bufix < cutoff)
486 buffer[bufix++] = '\0';
487 else
488 goto zapfrags;
489 }
490 if (code == DHO_CLASSLESS_STATIC_ROUTES ||
491 code == DHO_CLASSLESS_MS_STATIC_ROUTES)
492 stored_classless = 1;
493 }
494
495 if (bufix == (4 + (overload ? 3 : 0)))
496 /* Didn't manage to store any options. */
497 return (0);
498
499 if (bufix < buflen)
500 buffer[bufix++] = DHO_END;
501
502 /* Fill in overload option value based on space used for options. */
503 if (overload) {
504 overflow = bufix - main_buffer_size;
505 if (overflow > 0) {
506 buffer[4] = DHO_DHCP_OPTION_OVERLOAD;
507 buffer[5] = 1;
508 if (overload & 1) {
509 buffer[6] |= 1;
510 overflow -= DHCP_FILE_LEN;
511 }
512 if ((overload & 2) && overflow > 0)
513 buffer[6] |= 2;
514 } else {
515 /*
516 * Compact buffer to eliminate the unused
517 * DHO_DHCP_OPTION_OVERLOAD option. Some clients
518 * choke on DHO_PAD options there.
519 */
520 memmove(&buffer[4], &buffer[7], buflen - 7);
521 bufix -= 3;
522 memset(&buffer[bufix], DHO_PAD, 3);
523 }
524 }
525
526 return (bufix);
527 }
528
529 void
do_packet(struct interface_info * interface,struct dhcp_packet * packet,int len,unsigned int from_port,struct iaddr from,struct hardware * hfrom)530 do_packet(struct interface_info *interface, struct dhcp_packet *packet,
531 int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom)
532 {
533 struct packet tp;
534 int i;
535
536 if (packet->hlen > sizeof(packet->chaddr)) {
537 log_info("Discarding packet with invalid hlen.");
538 return;
539 }
540
541 memset(&tp, 0, sizeof(tp));
542 tp.raw = packet;
543 tp.packet_length = len;
544 tp.client_port = from_port;
545 tp.client_addr = from;
546 tp.interface = interface;
547 tp.haddr = hfrom;
548
549 parse_options(&tp);
550 if (tp.options_valid &&
551 tp.options[DHO_DHCP_MESSAGE_TYPE].data)
552 tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0];
553
554 if (tp.packet_type)
555 dhcp(&tp, interface->is_udpsock);
556 else
557 bootp(&tp);
558
559 /* Free the data associated with the options. */
560 for (i = 0; i < 256; i++)
561 free(tp.options[i].data);
562 }
563