summaryrefslogtreecommitdiff
path: root/common/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/options.c')
-rw-r--r--common/options.c520
1 files changed, 0 insertions, 520 deletions
diff --git a/common/options.c b/common/options.c
deleted file mode 100644
index 354c10a4..00000000
--- a/common/options.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* options.c
-
- DHCP options parsing and reassembly. */
-
-/*
- * Copyright (c) 1995, 1996 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
-#endif /* not lint */
-
-#define DHCP_OPTION_DATA
-#include "dhcpd.h"
-
-/* Parse all available options out of the specified packet. */
-
-void parse_options (packet)
- struct packet *packet;
-{
- /* Initially, zero all option pointers. */
- memset (packet -> options, 0, sizeof (packet -> options));
-
- /* If we don't see the magic cookie, there's nothing to parse. */
- if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
- packet -> options_valid = 0;
- return;
- }
-
- /* Go through the options field, up to the end of the packet
- or the End field. */
- parse_option_buffer (packet, &packet -> raw -> options [4],
- packet -> packet_length - DHCP_FIXED_NON_UDP + 4);
- /* If we parsed a DHCP Option Overload option, parse more
- options out of the buffer(s) containing them. */
- if (packet -> options_valid
- && packet -> options [DHO_DHCP_OPTION_OVERLOAD].data) {
- if (packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)
- parse_option_buffer (packet,
- packet -> raw -> file,
- sizeof packet -> raw -> file);
- if (packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)
- parse_option_buffer (packet,
- packet -> raw -> sname,
- sizeof packet -> raw -> sname);
- }
-}
-
-/* Parse options out of the specified buffer, storing addresses of option
- values in packet -> options and setting packet -> options_valid if no
- errors are encountered. */
-
-void parse_option_buffer (packet, buffer, length)
- struct packet *packet;
- unsigned char *buffer;
- int length;
-{
- unsigned char *s, *t;
- unsigned char *end = buffer + length;
- int len;
- int code;
-
- for (s = buffer; *s != DHO_END && s < end; ) {
- code = s [0];
- /* Pad options don't have a length - just skip them. */
- if (code == DHO_PAD) {
- ++s;
- continue;
- }
- /* All other fields (except end, see above) have a
- one-byte length. */
- len = s [1];
-
- /* If the length is outrageous, the options are bad. */
- if (s + len + 2 > end) {
- warn ("Option %s length %d overflows input buffer.",
- dhcp_options [code].name,
- len);
- packet -> options_valid = 0;
- return;
- }
- /* If we haven't seen this option before, just make
- space for it and copy it there. */
- if (!packet -> options [code].data) {
- if (!(t = (unsigned char *)malloc (len + 1)))
- error ("Can't allocate storage for option %s.",
- dhcp_options [code].name);
- /* Copy and NUL-terminate the option (in case it's an
- ASCII string. */
- memcpy (t, &s [2], len);
- t [len] = 0;
- packet -> options [code].len = len;
- packet -> options [code].data = t;
- } else {
- /* If it's a repeat, concatenate it to whatever
- we last saw. This is really only required
- for clients, but what the heck... */
- t = (unsigned char *)
- malloc (len + packet -> options [code].len);
- if (!t)
- error ("Can't expand storage for option %s.",
- dhcp_options [code].name);
- memcpy (t, packet -> options [code].data,
- packet -> options [code].len);
- memcpy (t + packet -> options [code].len,
- &s [2], len);
- packet -> options [code].len += len;
- t [packet -> options [code].len] = 0;
- free (packet -> options [code].data);
- packet -> options [code].data = t;
- }
- s += len + 2;
- }
- packet -> options_valid = 1;
-}
-
-/* cons options into a big buffer, and then split them out into the
- three seperate buffers if needed. This allows us to cons up a set
- of vendor options using the same routine. */
-
-void cons_options (inpacket, outpacket, options, overload)
- struct packet *inpacket;
- struct packet *outpacket;
- struct tree_cache **options;
- int overload; /* Overload flags that may be set. */
-{
- unsigned char priority_list [300];
- int priority_len;
- unsigned char buffer [4096]; /* Really big buffer... */
- int main_buffer_size;
- int mainbufix, bufix;
- int option_size;
- int result;
- int i;
-
- /* If the client has provided a maximum DHCP message size,
- use that. Otherwise, we use the default MTU size (576 bytes). */
- /* XXX Maybe it would be safe to assume that we can send a packet
- to the client that's as big as the one it sent us, even if it
- didn't specify a large MTU. */
- if (inpacket && inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data) {
- main_buffer_size =
- (getUShort (inpacket -> options
- [DHO_DHCP_MAX_MESSAGE_SIZE].data)
- - DHCP_FIXED_LEN);
- /* Enforce a minimum packet size... */
- if (main_buffer_size < (576 - DHCP_FIXED_LEN))
- main_buffer_size = 576 - DHCP_FIXED_LEN;
- } else
- main_buffer_size = 576 - DHCP_FIXED_LEN;
-
- /* Preload the option priority list with mandatory options. */
- priority_len = 0;
- priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE;
- priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
- priority_list [priority_len++] = DHO_DHCP_LEASE_TIME;
- priority_list [priority_len++] = DHO_DHCP_MESSAGE;
-
- /* If the client has provided a list of options that it wishes
- returned, use it to prioritize. Otherwise, prioritize
- based on the default priority list. */
-
- if (inpacket &&
- inpacket -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data) {
- memcpy (&priority_list [priority_len],
- inpacket -> options
- [DHO_DHCP_PARAMETER_REQUEST_LIST].data,
- inpacket -> options
- [DHO_DHCP_PARAMETER_REQUEST_LIST].len);
- priority_len +=
- inpacket -> options
- [DHO_DHCP_PARAMETER_REQUEST_LIST].len;
- } else {
- memcpy (&priority_list [priority_len],
- dhcp_option_default_priority_list,
- sizeof_dhcp_option_default_priority_list);
- priority_len += sizeof_dhcp_option_default_priority_list;
- }
-
- /* Copy the options into the big buffer... */
- option_size = store_options (buffer,
- (main_buffer_size - 7 +
- ((overload & 1) ? DHCP_FILE_LEN : 0) +
- ((overload & 2) ? DHCP_SNAME_LEN : 0)),
- options, priority_list, priority_len,
- main_buffer_size,
- (main_buffer_size +
- ((overload & 1) ? DHCP_FILE_LEN : 0)));
-
- /* Put the cookie up front... */
- memcpy (outpacket -> raw -> options, DHCP_OPTIONS_COOKIE, 4);
- mainbufix = 4;
-
- /* If we're going to have to overload, store the overload
- option at the beginning. If we can, though, just store the
- whole thing in the packet's option buffer and leave it at
- that. */
- if (option_size <= main_buffer_size - mainbufix) {
- memcpy (&outpacket -> raw -> options [mainbufix],
- buffer, option_size);
- mainbufix += option_size;
- if (mainbufix < main_buffer_size)
- outpacket -> raw -> options [mainbufix++]
- = DHO_END;
- outpacket -> packet_length = DHCP_FIXED_NON_UDP + mainbufix;
- } else {
- outpacket -> raw -> options [mainbufix++] =
- DHO_DHCP_OPTION_OVERLOAD;
- outpacket -> raw -> options [mainbufix++] = 1;
- if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN)
- outpacket -> raw -> options [mainbufix++] = 3;
- else
- outpacket -> raw -> options [mainbufix++] = 1;
-
- memcpy (&outpacket -> raw -> options [mainbufix],
- buffer, main_buffer_size - mainbufix);
- bufix = main_buffer_size - mainbufix;
- outpacket -> packet_length = DHCP_FIXED_NON_UDP + mainbufix;
- if (overload & 1) {
- if (option_size - bufix <= DHCP_FILE_LEN) {
- memcpy (outpacket -> raw -> file,
- &buffer [bufix], option_size - bufix);
- mainbufix = option_size - bufix;
- if (mainbufix < DHCP_FILE_LEN)
- outpacket -> raw -> file [mainbufix++]
- = DHO_END;
- while (mainbufix < DHCP_FILE_LEN)
- outpacket -> raw -> file [mainbufix++]
- = DHO_PAD;
- } else {
- memcpy (outpacket -> raw -> file,
- &buffer [bufix], DHCP_FILE_LEN);
- bufix += DHCP_FILE_LEN;
- }
- }
- if ((overload & 2) && option_size < bufix) {
- memcpy (outpacket -> raw -> sname,
- &buffer [bufix], option_size - bufix);
-
- mainbufix = option_size - bufix;
- if (mainbufix < DHCP_SNAME_LEN)
- outpacket -> raw -> file [mainbufix++]
- = DHO_END;
- while (mainbufix < DHCP_SNAME_LEN)
- outpacket -> raw -> file [mainbufix++]
- = DHO_PAD;
- }
- }
- return;
-}
-
-/* Store all the requested options into the requested buffer. */
-
-int store_options (buffer, buflen, options, priority_list, priority_len,
- first_cutoff, second_cutoff)
- unsigned char *buffer;
- int buflen;
- struct tree_cache **options;
- unsigned char *priority_list;
- int priority_len;
- int first_cutoff, second_cutoff;
-{
- int bufix = 0;
- int option_stored [256];
- int missed = 0;
- int missed_code = 0;
- int missed_length = 0;
- int result;
- int i;
- int ix;
-
- /* Zero out the stored-lengths array. */
- memset (option_stored, 0, sizeof option_stored);
-
- /* Copy out the options in the order that they appear in the
- priority list... */
- for (i = 0; i < priority_len; i++) {
- /* Code for next option to try to store. */
- int code = priority_list [i];
- int optstart;
-
- /* Number of bytes left to store (some may already
- have been stored by a previous pass). */
- int length;
-
- /* If no data is available for this option, skip it. */
- if (!options [code]) {
- continue;
- }
-
- /* The client could ask for things that are mandatory,
- in which case we should avoid storing them twice... */
- if (option_stored [code])
- continue;
- option_stored [code] = 1;
-
- /* Find the value of the option... */
- if (!tree_evaluate (options [code])) {
- continue;
- }
-
- /* We should now have a constant length for the option. */
- length = options [code] -> len;
-
- /* Try to store the option. */
-
- /* If the option's length is more than 255, we must store it
- in multiple hunks. Store 255-byte hunks first. However,
- in any case, if the option data will cross a buffer
- boundary, split it across that boundary. */
-
- ix = 0;
-
- optstart = bufix;
- while (length) {
- unsigned char incr = length > 255 ? 255 : length;
-
- /* If this hunk of the buffer will cross a
- boundary, only go up to the boundary in this
- pass. */
- if (bufix < first_cutoff &&
- bufix + incr > first_cutoff)
- incr = first_cutoff - bufix;
- else if (bufix < second_cutoff &&
- bufix + incr > second_cutoff)
- incr = second_cutoff - bufix;
-
- /* If this option is going to overflow the buffer,
- skip it. */
- if (bufix + 2 + incr > buflen) {
- bufix = optstart;
- break;
- }
-
- /* Everything looks good - copy it in! */
- buffer [bufix] = code;
- buffer [bufix + 1] = incr;
- memcpy (buffer + bufix + 2,
- options [code] -> value + ix, incr);
- length -= incr;
- ix += incr;
- bufix += 2 + incr;
- }
- }
- return bufix;
-}
-
-/* Format the specified option so that a human can easily read it. */
-
-char *pretty_print_option (code, data, len)
- unsigned char code;
- unsigned char *data;
- int len;
-{
- static char optbuf [32768]; /* XXX */
- int hunksize = 0;
- int numhunk = -1;
- int numelem = 0;
- char fmtbuf [32];
- int i, j;
- char *op = optbuf;
- unsigned char *dp = data;
- struct in_addr foo;
-
- /* Figure out the size of the data. */
- for (i = 0; dhcp_options [code].format [i]; i++) {
- if (!numhunk) {
- warn ("%s: Excess information in format string: %s\n",
- dhcp_options [code].name,
- &(dhcp_options [code].format [i]));
- break;
- }
- numelem++;
- fmtbuf [i] = dhcp_options [code].format [i];
- switch (dhcp_options [code].format [i]) {
- case 'A':
- --numelem;
- fmtbuf [i] = 0;
- numhunk = 0;
- break;
- case 't':
- fmtbuf [i] = 't';
- fmtbuf [i + 1] = 0;
- numhunk = -2;
- break;
- case 'I':
- case 'l':
- case 'L':
- hunksize += 4;
- break;
- case 's':
- case 'S':
- hunksize += 2;
- break;
- case 'b':
- case 'B':
- case 'f':
- hunksize++;
- break;
- case 'e':
- break;
- default:
- warn ("%s: garbage in format string: %s\n",
- dhcp_options [code].name,
- &(dhcp_options [code].format [i]));
- break;
- }
- }
-
- /* Check for too few bytes... */
- if (hunksize > len) {
- warn ("%s: expecting at least %d bytes; got %d",
- dhcp_options [code].name,
- hunksize, len);
- return "<error>";
- }
- /* Check for too many bytes... */
- if (numhunk == -1 && hunksize < len)
- warn ("%s: %d extra bytes",
- dhcp_options [code].name,
- len - hunksize);
-
- /* If this is an array, compute its size. */
- if (!numhunk)
- numhunk = len / hunksize;
- /* See if we got an exact number of hunks. */
- if (numhunk > 0 && numhunk * hunksize < len)
- warn ("%s: %d extra bytes at end of array\n",
- dhcp_options [code].name,
- len - numhunk * hunksize);
-
- /* A one-hunk array prints the same as a single hunk. */
- if (numhunk < 0)
- numhunk = 1;
-
- /* Cycle through the array (or hunk) printing the data. */
- for (i = 0; i < numhunk; i++) {
- for (j = 0; j < numelem; j++) {
- switch (fmtbuf [j]) {
- case 't':
- strcpy (op, dp);
- break;
- case 'I':
- foo.s_addr = htonl (getULong (dp));
- strcpy (op, inet_ntoa (foo));
- dp += 4;
- break;
- case 'l':
- sprintf (op, "%ld", getLong (dp));
- dp += 4;
- break;
- case 'L':
- sprintf (op, "%ld", getULong (dp));
- dp += 4;
- break;
- case 's':
- sprintf (op, "%d", getShort (dp));
- dp += 2;
- break;
- case 'S':
- sprintf (op, "%d", getUShort (dp));
- dp += 2;
- break;
- case 'b':
- sprintf (op, "%d", *(char *)dp++);
- break;
- case 'B':
- sprintf (op, "%d", *dp++);
- break;
- case 'f':
- strcpy (op, *dp++ ? "true" : "false");
- break;
- default:
- warn ("Unexpected format code %c", fmtbuf [j]);
- }
- op += strlen (op);
- *op++ = ' ';
- }
- }
- *--op = 0;
- return optbuf;
-}
-
-
-