2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-31 14:25:41 +00:00

- Reworked cons_options() and store_options() to fix a buffer

overflow that could result in a DoS (CVS 2007-0062).  Also general
  code tidying. [rt17090]
- Also fixed a spurious error message on the client. [rt17250]
This commit is contained in:
Evan Hunt
2007-10-26 22:46:50 +00:00
parent 6b911c8634
commit e2624b82f1
5 changed files with 271 additions and 236 deletions

View File

@@ -1410,7 +1410,7 @@ struct client_lease *packet_to_lease (packet, client)
if (!(i & 2) && packet -> raw -> sname [0]) { if (!(i & 2) && packet -> raw -> sname [0]) {
unsigned len; unsigned len;
/* Don't count on the NUL terminator. */ /* Don't count on the NUL terminator. */
for (len = 0; len < 64; len++) for (len = 0; len < DHCP_SNAME_LEN; len++)
if (!packet -> raw -> sname [len]) if (!packet -> raw -> sname [len])
break; break;
lease -> server_name = dmalloc (len + 1, MDL); lease -> server_name = dmalloc (len + 1, MDL);
@@ -1429,7 +1429,7 @@ struct client_lease *packet_to_lease (packet, client)
if (!(i & 1) && packet -> raw -> file [0]) { if (!(i & 1) && packet -> raw -> file [0]) {
unsigned len; unsigned len;
/* Don't count on the NUL terminator. */ /* Don't count on the NUL terminator. */
for (len = 0; len < 64; len++) for (len = 0; len < DHCP_FILE_LEN; len++)
if (!packet -> raw -> file [len]) if (!packet -> raw -> file [len])
break; break;
lease -> filename = dmalloc (len + 1, MDL); lease -> filename = dmalloc (len + 1, MDL);

View File

@@ -505,94 +505,129 @@ int fqdn_universe_decode (struct option_state *options,
return 1; return 1;
} }
/* cons options into a big buffer, and then split them out into the /*
three separate buffers if needed. This allows us to cons up a set * Load all options into a buffer, and then split them out into the three
of vendor options using the same routine. */ * separate fields in the dhcp packet (options, file, and sname) where
* options can be stored.
int cons_options (inpacket, outpacket, lease, client_state, */
mms, in_options, cfg_options, int
scope, overload, terminate, bootpp, prl, vuname) cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
struct packet *inpacket; struct lease *lease, struct client_state *client_state,
struct dhcp_packet *outpacket; int mms, struct option_state *in_options,
struct lease *lease; struct option_state *cfg_options,
struct client_state *client_state; struct binding_scope **scope,
int mms; int overload_avail, int terminate, int bootpp,
struct option_state *in_options; struct data_string *prl, const char *vuname)
struct option_state *cfg_options;
struct binding_scope **scope;
int overload; /* Overload flags that may be set. */
int terminate;
int bootpp;
struct data_string *prl;
const char *vuname;
{ {
#define PRIORITY_COUNT 300 #define PRIORITY_COUNT 300
unsigned priority_list [PRIORITY_COUNT]; unsigned priority_list[PRIORITY_COUNT];
int priority_len; int priority_len;
unsigned char buffer [4096]; /* Really big buffer... */ unsigned char buffer[4096], agentopts[1024];
unsigned main_buffer_size, mb_max; unsigned index = 0;
unsigned mainbufix, agentix; unsigned mb_size = 0, mb_max = 0;
unsigned option_size; unsigned option_size = 0, agent_size = 0;
unsigned length; unsigned length;
int i; int i;
struct option_cache *op; struct option_cache *op;
struct data_string ds; struct data_string ds;
pair pp, *hash; pair pp, *hash;
int need_endopt = 0; int overload_used = 0;
int ocount = 0; int of1 = 0, of2 = 0;
int ofbuf1=0, ofbuf2=0;
memset (&ds, 0, sizeof ds); memset(&ds, 0, sizeof ds);
/* If there's a Maximum Message Size option in the incoming packet /*
and no alternate maximum message size has been specified, take the * If there's a Maximum Message Size option in the incoming packet
one in the packet. */ * and no alternate maximum message size has been specified, or
* if the one specified in the packet is shorter than the
* alternative, take the one in the packet.
*/
if (inpacket && if (inpacket &&
(op = lookup_option (&dhcp_universe, inpacket -> options, (op = lookup_option(&dhcp_universe, inpacket->options,
DHO_DHCP_MAX_MESSAGE_SIZE))) { DHO_DHCP_MAX_MESSAGE_SIZE))) {
evaluate_option_cache (&ds, inpacket, evaluate_option_cache(&ds, inpacket,
lease, client_state, in_options, lease, client_state, in_options,
cfg_options, scope, op, MDL); cfg_options, scope, op, MDL);
if (ds.len >= sizeof (u_int16_t)) { if (ds.len >= sizeof (u_int16_t)) {
i = getUShort (ds.data); i = getUShort(ds.data);
if(!mms || (i < mms)) if(!mms || (i < mms))
mms = i; mms = i;
} }
data_string_forget (&ds, MDL); data_string_forget(&ds, MDL);
} }
/* If the client has provided a maximum DHCP message size, /*
use that; otherwise, if it's BOOTP, only 64 bytes; otherwise * If the client has provided a maximum DHCP message size,
use up to the minimum IP MTU size (576 bytes). */ * use that, up to the MTU limit. Otherwise, if it's BOOTP,
/* XXX if a BOOTP client specifies a max message size, we will * only 64 bytes; otherwise use up to the minimum IP MTU size
honor it. */ * (576 bytes).
*
* XXX if a BOOTP client specifies a max message size, we will
* honor it.
*/
if (mms) { if (mms) {
main_buffer_size = mms - DHCP_FIXED_LEN; if (mms < DHCP_MTU_MIN)
/* Enforce minimum packet size, per RFC 2132 */
/* Enforce a minimum packet size... */ mb_size = DHCP_MIN_OPTION_LEN;
if (main_buffer_size < (576 - DHCP_FIXED_LEN)) else if (mms > DHCP_MTU_MAX)
main_buffer_size = 576 - DHCP_FIXED_LEN; /*
* TODO: Packets longer than 1500 bytes really
* should be allowed, but it requires upstream
* changes to the way the packet is allocated. For
* now, we forbid them. They won't be needed very
* often anyway.
*/
mb_size = DHCP_MAX_OPTION_LEN;
else
mb_size = mms - DHCP_FIXED_LEN;
} else if (bootpp) { } else if (bootpp) {
if (inpacket) { mb_size = 64;
main_buffer_size = if (inpacket != NULL &&
inpacket -> packet_length - DHCP_FIXED_LEN; (inpacket->packet_length - DHCP_FIXED_LEN >= 64))
if (main_buffer_size < 64) mb_size = inpacket->packet_length - DHCP_FIXED_LEN;
main_buffer_size = 64;
} else
main_buffer_size = 64;
} else } else
main_buffer_size = 576 - DHCP_FIXED_LEN; mb_size = DHCP_MIN_OPTION_LEN;
/* Set a hard limit at the size of the output buffer. */ /*
mb_max = sizeof(buffer) - (((overload & 1) ? DHCP_FILE_LEN : 0) + * If answering a client message, see whether any relay agent
((overload & 2) ? DHCP_SNAME_LEN : 0)); * options were included with the message. If so, save them
if (main_buffer_size > mb_max) * to copy back in later, and make space in the main buffer
main_buffer_size = mb_max; * to accomodate them
*/
if (client_state == NULL) {
priority_list[0] = DHO_DHCP_AGENT_OPTIONS;
priority_len = 1;
agent_size = store_options(NULL, agentopts, 0,
sizeof(agentopts),
inpacket, lease, client_state,
in_options, cfg_options, scope,
priority_list, priority_len,
0, 0, 0, NULL);
/* Preload the option priority list with protocol-mandatory options. mb_size += agent_size;
if (mb_size > DHCP_MAX_OPTION_LEN)
mb_size = DHCP_MAX_OPTION_LEN;
}
/*
* Set offsets for buffer data to be copied into filename
* and servername fields
*/
mb_max = mb_size;
if (overload_avail & 1) {
of1 = mb_max;
mb_max += DHCP_FILE_LEN;
}
if (overload_avail & 2) {
of2 = mb_max;
mb_max += DHCP_SNAME_LEN;
}
/*
* Preload the option priority list with protocol-mandatory options.
* This effectively gives these options the highest priority. * This effectively gives these options the highest priority.
*/ */
priority_len = 0; priority_len = 0;
@@ -603,25 +638,27 @@ int cons_options (inpacket, outpacket, lease, client_state,
priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS; priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
priority_list[priority_len++] = DHO_ASSOCIATED_IP; priority_list[priority_len++] = DHO_ASSOCIATED_IP;
if (prl && prl -> len > 0) { if (prl != NULL && prl->len > 0) {
if ((op = lookup_option (&dhcp_universe, cfg_options, if ((op = lookup_option(&dhcp_universe, cfg_options,
DHO_SUBNET_SELECTION))) { DHO_SUBNET_SELECTION))) {
if (priority_len < PRIORITY_COUNT) if (priority_len < PRIORITY_COUNT)
priority_list [priority_len++] = priority_list[priority_len++] =
DHO_SUBNET_SELECTION; DHO_SUBNET_SELECTION;
} }
data_string_truncate (prl, (PRIORITY_COUNT - priority_len)); data_string_truncate(prl, (PRIORITY_COUNT - priority_len));
for (i = 0; i < prl -> len; i++) { for (i = 0; i < prl->len; i++) {
/* Prevent client from changing order of delivery /*
of relay agent information option. */ * Prevent client from changing order of delivery
if (prl -> data [i] != DHO_DHCP_AGENT_OPTIONS) * of relay agent information option.
priority_list [priority_len++] = */
prl -> data [i]; if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS)
priority_list[priority_len++] = prl->data[i];
} }
/* If the client doesn't request the FQDN option explicitly, /*
* If the client doesn't request the FQDN option explicitly,
* to indicate priority, consider it lowest priority. Fit * to indicate priority, consider it lowest priority. Fit
* in the packet if there is space. Note that the option * in the packet if there is space. Note that the option
* may only be included if the client supplied one. * may only be included if the client supplied one.
@@ -631,7 +668,8 @@ int cons_options (inpacket, outpacket, lease, client_state,
DHO_FQDN) != NULL)) DHO_FQDN) != NULL))
priority_list[priority_len++] = DHO_FQDN; priority_list[priority_len++] = DHO_FQDN;
/* Some DHCP Servers will give the subnet-mask option if /*
* Some DHCP Servers will give the subnet-mask option if
* it is not on the parameter request list - so some client * it is not on the parameter request list - so some client
* implementations have come to rely on this - so we will * implementations have come to rely on this - so we will
* also make sure we supply this, at lowest priority. * also make sure we supply this, at lowest priority.
@@ -645,9 +683,9 @@ int cons_options (inpacket, outpacket, lease, client_state,
((inpacket->packet_type == DHCPDISCOVER) || ((inpacket->packet_type == DHCPDISCOVER) ||
(inpacket->packet_type == DHCPREQUEST))) (inpacket->packet_type == DHCPREQUEST)))
priority_list[priority_len++] = DHO_SUBNET_MASK; priority_list[priority_len++] = DHO_SUBNET_MASK;
} else { } else {
/* First, hardcode some more options that ought to be /*
* First, hardcode some more options that ought to be
* sent first...these are high priority to have in the * sent first...these are high priority to have in the
* packet. * packet.
*/ */
@@ -657,154 +695,131 @@ int cons_options (inpacket, outpacket, lease, client_state,
priority_list[priority_len++] = DHO_HOST_NAME; priority_list[priority_len++] = DHO_HOST_NAME;
priority_list[priority_len++] = DHO_FQDN; priority_list[priority_len++] = DHO_FQDN;
/* Append a list of the standard DHCP options from the /*
standard DHCP option space. Actually, if a site * Append a list of the standard DHCP options from the
option space hasn't been specified, we wind up * standard DHCP option space. Actually, if a site
treating the dhcp option space as the site option * option space hasn't been specified, we wind up
space, and the first for loop is skipped, because * treating the dhcp option space as the site option
it's slightly more general to do it this way, * space, and the first for loop is skipped, because
taking the 1Q99 DHCP futures work into account. */ * it's slightly more general to do it this way,
if (cfg_options -> site_code_min) { * taking the 1Q99 DHCP futures work into account.
*/
if (cfg_options->site_code_min) {
for (i = 0; i < OPTION_HASH_SIZE; i++) { for (i = 0; i < OPTION_HASH_SIZE; i++) {
hash = cfg_options -> universes [dhcp_universe.index]; hash = cfg_options->universes[dhcp_universe.index];
if (hash) { if (hash) {
for (pp = hash [i]; pp; pp = pp -> cdr) { for (pp = hash[i]; pp; pp = pp->cdr) {
op = (struct option_cache *)(pp -> car); op = (struct option_cache *)(pp->car);
if (op -> option -> code < if (op->option->code <
cfg_options -> site_code_min && cfg_options->site_code_min &&
priority_len < PRIORITY_COUNT && priority_len < PRIORITY_COUNT &&
(op -> option -> code != op->option->code != DHO_DHCP_AGENT_OPTIONS)
DHO_DHCP_AGENT_OPTIONS)) priority_list[priority_len++] =
priority_list [priority_len++] = op->option->code;
op -> option -> code;
} }
} }
} }
} }
/* Now cycle through the site option space, or if there /*
is no site option space, we'll be cycling through the * Now cycle through the site option space, or if there
dhcp option space. */ * is no site option space, we'll be cycling through the
* dhcp option space.
*/
for (i = 0; i < OPTION_HASH_SIZE; i++) { for (i = 0; i < OPTION_HASH_SIZE; i++) {
hash = (cfg_options -> universes hash = cfg_options->universes[cfg_options->site_universe];
[cfg_options -> site_universe]); if (hash != NULL)
if (hash) for (pp = hash[i]; pp; pp = pp->cdr) {
for (pp = hash [i]; pp; pp = pp -> cdr) { op = (struct option_cache *)(pp->car);
op = (struct option_cache *)(pp -> car); if (op->option->code >=
if (op -> option -> code >= cfg_options->site_code_min &&
cfg_options -> site_code_min &&
priority_len < PRIORITY_COUNT && priority_len < PRIORITY_COUNT &&
(op -> option -> code != op->option->code != DHO_DHCP_AGENT_OPTIONS)
DHO_DHCP_AGENT_OPTIONS)) priority_list[priority_len++] =
priority_list [priority_len++] = op->option->code;
op -> option -> code;
} }
} }
/* Put any spaces that are encapsulated on the list, /*
* Put any spaces that are encapsulated on the list,
* sort out whether they contain values later. * sort out whether they contain values later.
*/ */
for (i = 0; i < cfg_options -> universe_count; i++) { for (i = 0; i < cfg_options->universe_count; i++) {
if (universes[i]->enc_opt && if (universes[i]->enc_opt &&
priority_len < PRIORITY_COUNT && priority_len < PRIORITY_COUNT &&
universes [i] -> enc_opt -> universe == &dhcp_universe) universes[i]->enc_opt->universe == &dhcp_universe) {
{ if (universes[i]->enc_opt->code !=
if (universes [i] -> enc_opt -> code !=
DHO_DHCP_AGENT_OPTIONS) DHO_DHCP_AGENT_OPTIONS)
priority_list [priority_len++] = priority_list[priority_len++] =
universes [i] -> enc_opt -> code; universes[i]->enc_opt->code;
} }
} }
/* The vendor option space can't stand on its own, so always /*
add it to the list. */ * The vendor option space can't stand on its own, so always
* add it to the list.
*/
if (priority_len < PRIORITY_COUNT) if (priority_len < PRIORITY_COUNT)
priority_list [priority_len++] = priority_list[priority_len++] =
DHO_VENDOR_ENCAPSULATED_OPTIONS; DHO_VENDOR_ENCAPSULATED_OPTIONS;
} }
/* Figure out the overload buffer offset(s). */ /* Put the cookie up front... */
if (overload) { memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
ofbuf1 = main_buffer_size - 4; index += 4;
if (overload == 3)
ofbuf2 = main_buffer_size - 4 + DHCP_FILE_LEN;
}
/* Copy the options into the big buffer... */ /* Copy the options into the big buffer... */
option_size = store_options (&ocount, buffer, option_size = store_options(&overload_used, buffer, index, mb_max,
(main_buffer_size - 4 + inpacket, lease, client_state,
((overload & 1) ? DHCP_FILE_LEN : 0) + in_options, cfg_options, scope,
((overload & 2) ? DHCP_SNAME_LEN : 0)), priority_list, priority_len,
inpacket, lease, client_state, of1, of2, terminate, vuname);
in_options, cfg_options, scope,
priority_list, priority_len, /* If store_options() failed */
ofbuf1, ofbuf2, terminate, vuname);
/* If store_options failed. */
if (option_size == 0) if (option_size == 0)
return 0; return 0;
if (overload) {
if (ocount == 1 && (overload & 1)) /* How much was stored in the main buffer? */
overload = 1; index += option_size;
else if (ocount == 1 && (overload & 2))
overload = 2; /*
else if (ocount == 3) * If we're going to have to overload, store the overload
overload = 3; * option first.
else */
overload = 0; if (overload_used) {
if (mb_size - agent_size - index < 3)
return 0;
buffer[index++] = DHO_DHCP_OPTION_OVERLOAD;
buffer[index++] = 1;
buffer[index++] = overload_used;
if (overload_used & 1)
memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN);
if (overload_used & 2)
memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN);
} }
/* Put the cookie up front... */ /* Now copy in preserved agent options, if any */
memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4); if (agent_size) {
mainbufix = 4; if (mb_size - index >= agent_size) {
memcpy(&buffer[index], agentopts, agent_size);
/* If we're going to have to overload, store the overload index += agent_size;
option at the beginning. If we can, though, just store the } else
whole thing in the packet's option buffer and leave it at log_error("Unable to store relay agent information"
that. */ "in reply packet.");
memcpy (&outpacket -> options [mainbufix],
buffer, option_size);
mainbufix += option_size;
if (overload) {
outpacket -> options [mainbufix++] = DHO_DHCP_OPTION_OVERLOAD;
outpacket -> options [mainbufix++] = 1;
outpacket -> options [mainbufix++] = overload;
if (overload & 1) {
memcpy (outpacket -> file,
&buffer [ofbuf1], DHCP_FILE_LEN);
}
if (overload & 2) {
if (ofbuf2) {
memcpy (outpacket -> sname, &buffer [ofbuf2],
DHCP_SNAME_LEN);
} else {
memcpy (outpacket -> sname, &buffer [ofbuf1],
DHCP_SNAME_LEN);
}
}
} }
agentix = mainbufix;
if (mainbufix < main_buffer_size)
need_endopt = 1;
length = DHCP_FIXED_NON_UDP + mainbufix;
/* Now hack in the agent options if there are any. */
priority_list [0] = DHO_DHCP_AGENT_OPTIONS;
priority_len = 1;
agentix +=
store_options (0, &outpacket -> options [agentix],
DHCP_OPTION_LEN - agentix,
inpacket, lease, client_state,
in_options, cfg_options, scope,
priority_list, priority_len,
0, 0, 0, (char *)0);
/* Tack a DHO_END option onto the packet if we need to. */ /* Tack a DHO_END option onto the packet if we need to. */
if (agentix < DHCP_OPTION_LEN && need_endopt) if (index < mb_size)
outpacket -> options [agentix++] = DHO_END; buffer[index++] = DHO_END;
/* Copy main buffer into the options buffer of the packet */
memcpy(outpacket->options, buffer, index);
/* Figure out the length. */ /* Figure out the length. */
length = DHCP_FIXED_NON_UDP + agentix; length = DHCP_FIXED_NON_UDP + index;
return length; return length;
} }
@@ -1066,25 +1081,21 @@ store_options6(char *buf, int buflen,
return bufpos; return bufpos;
} }
/* Store all the requested options into the requested buffer. */ /*
* Store all the requested options into the requested buffer.
int store_options (ocount, buffer, buflen, packet, lease, client_state, * XXX: ought to be static
in_options, cfg_options, scope, priority_list, priority_len, */
first_cutoff, second_cutoff, terminate, vuname) int
int *ocount; store_options(int *ocount,
unsigned char *buffer; unsigned char *buffer, unsigned index, unsigned buflen,
unsigned buflen; struct packet *packet, struct lease *lease,
struct packet *packet; struct client_state *client_state,
struct lease *lease; struct option_state *in_options,
struct client_state *client_state; struct option_state *cfg_options,
struct option_state *in_options; struct binding_scope **scope,
struct option_state *cfg_options; unsigned *priority_list, int priority_len,
struct binding_scope **scope; unsigned first_cutoff, int second_cutoff, int terminate,
unsigned *priority_list; const char *vuname)
int priority_len;
unsigned first_cutoff, second_cutoff;
int terminate;
const char *vuname;
{ {
int bufix = 0, six = 0, tix = 0; int bufix = 0, six = 0, tix = 0;
int i; int i;
@@ -1093,24 +1104,39 @@ int store_options (ocount, buffer, buflen, packet, lease, client_state,
int bufend, sbufend; int bufend, sbufend;
struct data_string od; struct data_string od;
struct option_cache *oc; struct option_cache *oc;
struct option *option=NULL; struct option *option = NULL;
unsigned code; unsigned code;
/*
* These arguments are relative to the start of the buffer, so
* reduce them by the current buffer index, and advance the
* buffer pointer to where we're going to start writing.
*/
buffer = &buffer[index];
buflen -= index;
if (first_cutoff)
first_cutoff -= index;
if (second_cutoff)
second_cutoff -= index;
/* Calculate the start and end of each section of the buffer */
bufend = sbufend = buflen;
if (first_cutoff) { if (first_cutoff) {
if (first_cutoff >= buflen) if (first_cutoff >= buflen)
log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL); log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
bufend = first_cutoff; bufend = first_cutoff;
} else
bufend = buflen;
if (second_cutoff) { if (second_cutoff) {
if (second_cutoff >= buflen)
log_fatal("%s:%d:store_options: Invalid second cutoff.",
MDL);
sbufend = second_cutoff;
}
} else if (second_cutoff) {
if (second_cutoff >= buflen) if (second_cutoff >= buflen)
log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL); log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
bufend = second_cutoff;
sbufend = second_cutoff; }
} else
sbufend = buflen;
memset (&od, 0, sizeof od); memset (&od, 0, sizeof od);
@@ -1428,7 +1454,8 @@ int store_options (ocount, buffer, buflen, packet, lease, client_state,
log_fatal("Second buffer overflow in overloaded options."); log_fatal("Second buffer overflow in overloaded options.");
buffer[first_cutoff + six] = DHO_END; buffer[first_cutoff + six] = DHO_END;
*ocount |= 1; /* So that caller knows there's data there. */ if (ocount != NULL)
*ocount |= 1; /* So that caller knows there's data there. */
} }
if (second_cutoff && tix) { if (second_cutoff && tix) {
@@ -1439,7 +1466,8 @@ int store_options (ocount, buffer, buflen, packet, lease, client_state,
log_fatal("Third buffer overflow in overloaded options."); log_fatal("Third buffer overflow in overloaded options.");
buffer[second_cutoff + tix] = DHO_END; buffer[second_cutoff + tix] = DHO_END;
*ocount |= 2; /* So that caller knows there's data there. */ if (ocount != NULL)
*ocount |= 2; /* So that caller knows there's data there. */
} }
if ((six || tix) && (bufix + 3 > bufend)) if ((six || tix) && (bufix + 3 > bufend))
@@ -2674,7 +2702,7 @@ int option_space_encapsulate (result, packet, lease, client_state,
universe_hash_lookup(&u, universe_hash, universe_hash_lookup(&u, universe_hash,
(const char *)name->data, name->len, MDL); (const char *)name->data, name->len, MDL);
if (u == NULL) { if (u == NULL) {
log_error("option_space_encapsulate: option space %.*s does " log_error("option_space_encapsulate: option space '%.*s' does "
"not exist, but is configured.", "not exist, but is configured.",
(int)name->len, name->data); (int)name->len, name->data);
return status; return status;
@@ -2685,7 +2713,7 @@ int option_space_encapsulate (result, packet, lease, client_state,
in_options, cfg_options, scope, u)) in_options, cfg_options, scope, u))
status = 1; status = 1;
} else } else
log_error("encapsulation requested for %s with no support.", log_error("encapsulation requested for '%s' with no support.",
name->data); name->data);
return status; return status;
@@ -2695,7 +2723,7 @@ int option_space_encapsulate (result, packet, lease, client_state,
* placed on the option buffer by the above (configuring a value in * placed on the option buffer by the above (configuring a value in
* the space over-rides any values in the child universe). * the space over-rides any values in the child universe).
* *
* Note that there are far fewer universes than there will every be * Note that there are far fewer universes than there will ever be
* options in any universe. So it is faster to traverse the * options in any universe. So it is faster to traverse the
* configured universes, checking if each is encapsulated in the * configured universes, checking if each is encapsulated in the
* current universe, and if so attempting to do so. * current universe, and if so attempting to do so.

View File

@@ -34,17 +34,19 @@
#define DHCP_H #define DHCP_H
#define DHCP_UDP_OVERHEAD (20 + /* IP header */ \ #define DHCP_UDP_OVERHEAD (20 + /* IP header */ \
8) /* UDP header */ 8) /* UDP header */
#define DHCP_SNAME_LEN 64 #define DHCP_SNAME_LEN 64
#define DHCP_FILE_LEN 128 #define DHCP_FILE_LEN 128
#define DHCP_FIXED_NON_UDP 236 #define DHCP_FIXED_NON_UDP 236
#define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD) #define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD)
/* Everything but options. */ /* Everything but options. */
#define DHCP_MTU_MAX 1500
#define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN)
#define BOOTP_MIN_LEN 300 #define BOOTP_MIN_LEN 300
#define DHCP_MIN_LEN 548
#define DHCP_MTU_MAX 1500
#define DHCP_MTU_MIN 576
#define DHCP_MAX_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN)
#define DHCP_MIN_OPTION_LEN (DHCP_MTU_MIN - DHCP_FIXED_LEN)
struct dhcp_packet { struct dhcp_packet {
u_int8_t op; /* 0: Message opcode/type */ u_int8_t op; /* 0: Message opcode/type */
@@ -61,7 +63,7 @@ struct dhcp_packet {
unsigned char chaddr [16]; /* 24: Client hardware address */ unsigned char chaddr [16]; /* 24: Client hardware address */
char sname [DHCP_SNAME_LEN]; /* 40: Server name */ char sname [DHCP_SNAME_LEN]; /* 40: Server name */
char file [DHCP_FILE_LEN]; /* 104: Boot filename */ char file [DHCP_FILE_LEN]; /* 104: Boot filename */
unsigned char options [DHCP_OPTION_LEN]; unsigned char options [DHCP_MAX_OPTION_LEN];
/* 212: Optional parameters /* 212: Optional parameters
(actual length dependent on MTU). */ (actual length dependent on MTU). */
}; };

View File

@@ -1399,12 +1399,17 @@ fqdn6_universe_decode(struct option_state *options,
struct universe *u); struct universe *u);
int append_option(struct data_string *dst, struct universe *universe, int append_option(struct data_string *dst, struct universe *universe,
struct option *option, struct data_string *src); struct option *option, struct data_string *src);
int store_options PROTO ((int *, unsigned char *, unsigned, struct packet *, int
struct lease *, struct client_state *, store_options(int *ocount,
struct option_state *, unsigned char *buffer, unsigned buflen, unsigned index,
struct option_state *, struct binding_scope **, struct packet *packet, struct lease *lease,
unsigned *, int, unsigned, unsigned, struct client_state *client_state,
int, const char *)); struct option_state *in_options,
struct option_state *cfg_options,
struct binding_scope **scope,
unsigned *priority_list, int priority_len,
unsigned first_cutoff, int second_cutoff, int terminate,
const char *vuname);
int store_options6(char *, int, struct option_state *, struct packet *, int store_options6(char *, int, struct option_state *, struct packet *,
const int *, struct data_string *); const int *, struct data_string *);
int format_has_text(const char *); int format_has_text(const char *);

View File

@@ -218,7 +218,7 @@ void bootp (packet)
lookup_option (&server_universe, options, lookup_option (&server_universe, options,
SV_ALWAYS_REPLY_RFC1048), MDL))) { SV_ALWAYS_REPLY_RFC1048), MDL))) {
memcpy (outgoing.raw -> options, memcpy (outgoing.raw -> options,
packet -> raw -> options, DHCP_OPTION_LEN); packet -> raw -> options, DHCP_MAX_OPTION_LEN);
outgoing.packet_length = BOOTP_MIN_LEN; outgoing.packet_length = BOOTP_MIN_LEN;
} else { } else {