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
59int bad_options = 0;
60int bad_options_max = 5;
61
62void	parse_options(struct packet *);
63void	parse_option_buffer(struct packet *, unsigned char *, int);
64void	create_priority_list(unsigned char *, unsigned char *, int);
65int	store_option_fragment(unsigned char *, int, unsigned char,
66	    int, unsigned char *);
67int	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 */
74void
75parse_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 */
115void
116parse_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 */
219void
220create_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 */
272int
273cons_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 */
370int
371store_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 */
397int
398store_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) {
481zapfrags:
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
529void
530do_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