mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-31 06:15:55 +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:
@@ -1410,7 +1410,7 @@ struct client_lease *packet_to_lease (packet, client)
|
||||
if (!(i & 2) && packet -> raw -> sname [0]) {
|
||||
unsigned len;
|
||||
/* 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])
|
||||
break;
|
||||
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]) {
|
||||
unsigned len;
|
||||
/* 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])
|
||||
break;
|
||||
lease -> filename = dmalloc (len + 1, MDL);
|
||||
|
470
common/options.c
470
common/options.c
@@ -505,94 +505,129 @@ int fqdn_universe_decode (struct option_state *options,
|
||||
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
|
||||
of vendor options using the same routine. */
|
||||
|
||||
int cons_options (inpacket, outpacket, lease, client_state,
|
||||
mms, in_options, cfg_options,
|
||||
scope, overload, terminate, bootpp, prl, vuname)
|
||||
struct packet *inpacket;
|
||||
struct dhcp_packet *outpacket;
|
||||
struct lease *lease;
|
||||
struct client_state *client_state;
|
||||
int mms;
|
||||
struct option_state *in_options;
|
||||
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;
|
||||
/*
|
||||
* Load all options into a buffer, and then split them out into the three
|
||||
* separate fields in the dhcp packet (options, file, and sname) where
|
||||
* options can be stored.
|
||||
*/
|
||||
int
|
||||
cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
|
||||
struct lease *lease, struct client_state *client_state,
|
||||
int mms, struct option_state *in_options,
|
||||
struct option_state *cfg_options,
|
||||
struct binding_scope **scope,
|
||||
int overload_avail, int terminate, int bootpp,
|
||||
struct data_string *prl, const char *vuname)
|
||||
{
|
||||
#define PRIORITY_COUNT 300
|
||||
unsigned priority_list [PRIORITY_COUNT];
|
||||
unsigned priority_list[PRIORITY_COUNT];
|
||||
int priority_len;
|
||||
unsigned char buffer [4096]; /* Really big buffer... */
|
||||
unsigned main_buffer_size, mb_max;
|
||||
unsigned mainbufix, agentix;
|
||||
unsigned option_size;
|
||||
unsigned char buffer[4096], agentopts[1024];
|
||||
unsigned index = 0;
|
||||
unsigned mb_size = 0, mb_max = 0;
|
||||
unsigned option_size = 0, agent_size = 0;
|
||||
unsigned length;
|
||||
int i;
|
||||
struct option_cache *op;
|
||||
struct data_string ds;
|
||||
pair pp, *hash;
|
||||
int need_endopt = 0;
|
||||
int ocount = 0;
|
||||
int ofbuf1=0, ofbuf2=0;
|
||||
int overload_used = 0;
|
||||
int of1 = 0, of2 = 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
|
||||
one in the packet. */
|
||||
/*
|
||||
* If there's a Maximum Message Size option in the incoming 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 &&
|
||||
(op = lookup_option (&dhcp_universe, inpacket -> options,
|
||||
(op = lookup_option(&dhcp_universe, inpacket->options,
|
||||
DHO_DHCP_MAX_MESSAGE_SIZE))) {
|
||||
evaluate_option_cache (&ds, inpacket,
|
||||
evaluate_option_cache(&ds, inpacket,
|
||||
lease, client_state, in_options,
|
||||
cfg_options, scope, op, MDL);
|
||||
if (ds.len >= sizeof (u_int16_t)) {
|
||||
i = getUShort (ds.data);
|
||||
|
||||
i = getUShort(ds.data);
|
||||
if(!mms || (i < mms))
|
||||
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
|
||||
use up to the minimum IP MTU size (576 bytes). */
|
||||
/* XXX if a BOOTP client specifies a max message size, we will
|
||||
honor it. */
|
||||
|
||||
/*
|
||||
* If the client has provided a maximum DHCP message size,
|
||||
* use that, up to the MTU limit. Otherwise, if it's BOOTP,
|
||||
* only 64 bytes; otherwise use up to the minimum IP MTU size
|
||||
* (576 bytes).
|
||||
*
|
||||
* XXX if a BOOTP client specifies a max message size, we will
|
||||
* honor it.
|
||||
*/
|
||||
if (mms) {
|
||||
main_buffer_size = mms - DHCP_FIXED_LEN;
|
||||
|
||||
/* Enforce a minimum packet size... */
|
||||
if (main_buffer_size < (576 - DHCP_FIXED_LEN))
|
||||
main_buffer_size = 576 - DHCP_FIXED_LEN;
|
||||
if (mms < DHCP_MTU_MIN)
|
||||
/* Enforce minimum packet size, per RFC 2132 */
|
||||
mb_size = DHCP_MIN_OPTION_LEN;
|
||||
else if (mms > DHCP_MTU_MAX)
|
||||
/*
|
||||
* 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) {
|
||||
if (inpacket) {
|
||||
main_buffer_size =
|
||||
inpacket -> packet_length - DHCP_FIXED_LEN;
|
||||
if (main_buffer_size < 64)
|
||||
main_buffer_size = 64;
|
||||
} else
|
||||
main_buffer_size = 64;
|
||||
mb_size = 64;
|
||||
if (inpacket != NULL &&
|
||||
(inpacket->packet_length - DHCP_FIXED_LEN >= 64))
|
||||
mb_size = inpacket->packet_length - DHCP_FIXED_LEN;
|
||||
} 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) +
|
||||
((overload & 2) ? DHCP_SNAME_LEN : 0));
|
||||
if (main_buffer_size > mb_max)
|
||||
main_buffer_size = mb_max;
|
||||
/*
|
||||
* If answering a client message, see whether any relay agent
|
||||
* options were included with the message. If so, save them
|
||||
* to copy back in later, and make space in the main buffer
|
||||
* 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.
|
||||
*/
|
||||
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_ASSOCIATED_IP;
|
||||
|
||||
if (prl && prl -> len > 0) {
|
||||
if ((op = lookup_option (&dhcp_universe, cfg_options,
|
||||
if (prl != NULL && prl->len > 0) {
|
||||
if ((op = lookup_option(&dhcp_universe, cfg_options,
|
||||
DHO_SUBNET_SELECTION))) {
|
||||
if (priority_len < PRIORITY_COUNT)
|
||||
priority_list [priority_len++] =
|
||||
priority_list[priority_len++] =
|
||||
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++) {
|
||||
/* Prevent client from changing order of delivery
|
||||
of relay agent information option. */
|
||||
if (prl -> data [i] != DHO_DHCP_AGENT_OPTIONS)
|
||||
priority_list [priority_len++] =
|
||||
prl -> data [i];
|
||||
for (i = 0; i < prl->len; i++) {
|
||||
/*
|
||||
* Prevent client from changing order of delivery
|
||||
* of relay agent information option.
|
||||
*/
|
||||
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
|
||||
* in the packet if there is space. Note that the option
|
||||
* may only be included if the client supplied one.
|
||||
@@ -631,7 +668,8 @@ int cons_options (inpacket, outpacket, lease, client_state,
|
||||
DHO_FQDN) != NULL))
|
||||
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
|
||||
* implementations have come to rely on this - so we will
|
||||
* 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 == DHCPREQUEST)))
|
||||
priority_list[priority_len++] = DHO_SUBNET_MASK;
|
||||
|
||||
} 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
|
||||
* 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_FQDN;
|
||||
|
||||
/* Append a list of the standard DHCP options from the
|
||||
standard DHCP option space. Actually, if a site
|
||||
option space hasn't been specified, we wind up
|
||||
treating the dhcp option space as the site option
|
||||
space, and the first for loop is skipped, because
|
||||
it's slightly more general to do it this way,
|
||||
taking the 1Q99 DHCP futures work into account. */
|
||||
if (cfg_options -> site_code_min) {
|
||||
/*
|
||||
* Append a list of the standard DHCP options from the
|
||||
* standard DHCP option space. Actually, if a site
|
||||
* option space hasn't been specified, we wind up
|
||||
* treating the dhcp option space as the site option
|
||||
* space, and the first for loop is skipped, because
|
||||
* it's slightly more general to do it this way,
|
||||
* taking the 1Q99 DHCP futures work into account.
|
||||
*/
|
||||
if (cfg_options->site_code_min) {
|
||||
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
||||
hash = cfg_options -> universes [dhcp_universe.index];
|
||||
hash = cfg_options->universes[dhcp_universe.index];
|
||||
if (hash) {
|
||||
for (pp = hash [i]; pp; pp = pp -> cdr) {
|
||||
op = (struct option_cache *)(pp -> car);
|
||||
if (op -> option -> code <
|
||||
cfg_options -> site_code_min &&
|
||||
for (pp = hash[i]; pp; pp = pp->cdr) {
|
||||
op = (struct option_cache *)(pp->car);
|
||||
if (op->option->code <
|
||||
cfg_options->site_code_min &&
|
||||
priority_len < PRIORITY_COUNT &&
|
||||
(op -> option -> code !=
|
||||
DHO_DHCP_AGENT_OPTIONS))
|
||||
priority_list [priority_len++] =
|
||||
op -> option -> code;
|
||||
op->option->code != DHO_DHCP_AGENT_OPTIONS)
|
||||
priority_list[priority_len++] =
|
||||
op->option->code;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now cycle through the site option space, or if there
|
||||
is no site option space, we'll be cycling through the
|
||||
dhcp option space. */
|
||||
/*
|
||||
* Now cycle through the site option space, or if there
|
||||
* is no site option space, we'll be cycling through the
|
||||
* dhcp option space.
|
||||
*/
|
||||
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
||||
hash = (cfg_options -> universes
|
||||
[cfg_options -> site_universe]);
|
||||
if (hash)
|
||||
for (pp = hash [i]; pp; pp = pp -> cdr) {
|
||||
op = (struct option_cache *)(pp -> car);
|
||||
if (op -> option -> code >=
|
||||
cfg_options -> site_code_min &&
|
||||
hash = cfg_options->universes[cfg_options->site_universe];
|
||||
if (hash != NULL)
|
||||
for (pp = hash[i]; pp; pp = pp->cdr) {
|
||||
op = (struct option_cache *)(pp->car);
|
||||
if (op->option->code >=
|
||||
cfg_options->site_code_min &&
|
||||
priority_len < PRIORITY_COUNT &&
|
||||
(op -> option -> code !=
|
||||
DHO_DHCP_AGENT_OPTIONS))
|
||||
priority_list [priority_len++] =
|
||||
op -> option -> code;
|
||||
op->option->code != DHO_DHCP_AGENT_OPTIONS)
|
||||
priority_list[priority_len++] =
|
||||
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.
|
||||
*/
|
||||
for (i = 0; i < cfg_options -> universe_count; i++) {
|
||||
for (i = 0; i < cfg_options->universe_count; i++) {
|
||||
if (universes[i]->enc_opt &&
|
||||
priority_len < PRIORITY_COUNT &&
|
||||
universes [i] -> enc_opt -> universe == &dhcp_universe)
|
||||
{
|
||||
if (universes [i] -> enc_opt -> code !=
|
||||
universes[i]->enc_opt->universe == &dhcp_universe) {
|
||||
if (universes[i]->enc_opt->code !=
|
||||
DHO_DHCP_AGENT_OPTIONS)
|
||||
priority_list [priority_len++] =
|
||||
universes [i] -> enc_opt -> code;
|
||||
priority_list[priority_len++] =
|
||||
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)
|
||||
priority_list [priority_len++] =
|
||||
priority_list[priority_len++] =
|
||||
DHO_VENDOR_ENCAPSULATED_OPTIONS;
|
||||
}
|
||||
|
||||
/* Figure out the overload buffer offset(s). */
|
||||
if (overload) {
|
||||
ofbuf1 = main_buffer_size - 4;
|
||||
if (overload == 3)
|
||||
ofbuf2 = main_buffer_size - 4 + DHCP_FILE_LEN;
|
||||
}
|
||||
/* Put the cookie up front... */
|
||||
memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
|
||||
index += 4;
|
||||
|
||||
/* Copy the options into the big buffer... */
|
||||
option_size = store_options (&ocount, buffer,
|
||||
(main_buffer_size - 4 +
|
||||
((overload & 1) ? DHCP_FILE_LEN : 0) +
|
||||
((overload & 2) ? DHCP_SNAME_LEN : 0)),
|
||||
inpacket, lease, client_state,
|
||||
in_options, cfg_options, scope,
|
||||
priority_list, priority_len,
|
||||
ofbuf1, ofbuf2, terminate, vuname);
|
||||
/* If store_options failed. */
|
||||
option_size = store_options(&overload_used, buffer, index, mb_max,
|
||||
inpacket, lease, client_state,
|
||||
in_options, cfg_options, scope,
|
||||
priority_list, priority_len,
|
||||
of1, of2, terminate, vuname);
|
||||
|
||||
/* If store_options() failed */
|
||||
if (option_size == 0)
|
||||
return 0;
|
||||
if (overload) {
|
||||
if (ocount == 1 && (overload & 1))
|
||||
overload = 1;
|
||||
else if (ocount == 1 && (overload & 2))
|
||||
overload = 2;
|
||||
else if (ocount == 3)
|
||||
overload = 3;
|
||||
else
|
||||
overload = 0;
|
||||
|
||||
/* How much was stored in the main buffer? */
|
||||
index += option_size;
|
||||
|
||||
/*
|
||||
* If we're going to have to overload, store the overload
|
||||
* option first.
|
||||
*/
|
||||
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... */
|
||||
memcpy (outpacket -> 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. */
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* Now copy in preserved agent options, if any */
|
||||
if (agent_size) {
|
||||
if (mb_size - index >= agent_size) {
|
||||
memcpy(&buffer[index], agentopts, agent_size);
|
||||
index += agent_size;
|
||||
} else
|
||||
log_error("Unable to store relay agent information"
|
||||
"in reply packet.");
|
||||
}
|
||||
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. */
|
||||
if (agentix < DHCP_OPTION_LEN && need_endopt)
|
||||
outpacket -> options [agentix++] = DHO_END;
|
||||
if (index < mb_size)
|
||||
buffer[index++] = DHO_END;
|
||||
|
||||
/* Copy main buffer into the options buffer of the packet */
|
||||
memcpy(outpacket->options, buffer, index);
|
||||
|
||||
/* Figure out the length. */
|
||||
length = DHCP_FIXED_NON_UDP + agentix;
|
||||
length = DHCP_FIXED_NON_UDP + index;
|
||||
return length;
|
||||
}
|
||||
|
||||
@@ -1066,25 +1081,21 @@ store_options6(char *buf, int buflen,
|
||||
return bufpos;
|
||||
}
|
||||
|
||||
/* Store all the requested options into the requested buffer. */
|
||||
|
||||
int store_options (ocount, buffer, buflen, packet, lease, client_state,
|
||||
in_options, cfg_options, scope, priority_list, priority_len,
|
||||
first_cutoff, second_cutoff, terminate, vuname)
|
||||
int *ocount;
|
||||
unsigned char *buffer;
|
||||
unsigned buflen;
|
||||
struct packet *packet;
|
||||
struct lease *lease;
|
||||
struct client_state *client_state;
|
||||
struct option_state *in_options;
|
||||
struct option_state *cfg_options;
|
||||
struct binding_scope **scope;
|
||||
unsigned *priority_list;
|
||||
int priority_len;
|
||||
unsigned first_cutoff, second_cutoff;
|
||||
int terminate;
|
||||
const char *vuname;
|
||||
/*
|
||||
* Store all the requested options into the requested buffer.
|
||||
* XXX: ought to be static
|
||||
*/
|
||||
int
|
||||
store_options(int *ocount,
|
||||
unsigned char *buffer, unsigned index, unsigned buflen,
|
||||
struct packet *packet, struct lease *lease,
|
||||
struct client_state *client_state,
|
||||
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 bufix = 0, six = 0, tix = 0;
|
||||
int i;
|
||||
@@ -1093,24 +1104,39 @@ int store_options (ocount, buffer, buflen, packet, lease, client_state,
|
||||
int bufend, sbufend;
|
||||
struct data_string od;
|
||||
struct option_cache *oc;
|
||||
struct option *option=NULL;
|
||||
struct option *option = NULL;
|
||||
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 >= buflen)
|
||||
log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
|
||||
|
||||
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)
|
||||
log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
|
||||
|
||||
sbufend = second_cutoff;
|
||||
} else
|
||||
sbufend = buflen;
|
||||
bufend = second_cutoff;
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
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) {
|
||||
@@ -1439,7 +1466,8 @@ int store_options (ocount, buffer, buflen, packet, lease, client_state,
|
||||
log_fatal("Third buffer overflow in overloaded options.");
|
||||
|
||||
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))
|
||||
@@ -2674,7 +2702,7 @@ int option_space_encapsulate (result, packet, lease, client_state,
|
||||
universe_hash_lookup(&u, universe_hash,
|
||||
(const char *)name->data, name->len, MDL);
|
||||
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.",
|
||||
(int)name->len, name->data);
|
||||
return status;
|
||||
@@ -2685,7 +2713,7 @@ int option_space_encapsulate (result, packet, lease, client_state,
|
||||
in_options, cfg_options, scope, u))
|
||||
status = 1;
|
||||
} else
|
||||
log_error("encapsulation requested for %s with no support.",
|
||||
log_error("encapsulation requested for '%s' with no support.",
|
||||
name->data);
|
||||
|
||||
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
|
||||
* 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
|
||||
* configured universes, checking if each is encapsulated in the
|
||||
* current universe, and if so attempting to do so.
|
||||
|
@@ -34,17 +34,19 @@
|
||||
#define DHCP_H
|
||||
|
||||
#define DHCP_UDP_OVERHEAD (20 + /* IP header */ \
|
||||
8) /* UDP header */
|
||||
8) /* UDP header */
|
||||
#define DHCP_SNAME_LEN 64
|
||||
#define DHCP_FILE_LEN 128
|
||||
#define DHCP_FIXED_NON_UDP 236
|
||||
#define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD)
|
||||
/* Everything but options. */
|
||||
#define DHCP_MTU_MAX 1500
|
||||
#define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN)
|
||||
|
||||
#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 {
|
||||
u_int8_t op; /* 0: Message opcode/type */
|
||||
@@ -61,7 +63,7 @@ struct dhcp_packet {
|
||||
unsigned char chaddr [16]; /* 24: Client hardware address */
|
||||
char sname [DHCP_SNAME_LEN]; /* 40: Server name */
|
||||
char file [DHCP_FILE_LEN]; /* 104: Boot filename */
|
||||
unsigned char options [DHCP_OPTION_LEN];
|
||||
unsigned char options [DHCP_MAX_OPTION_LEN];
|
||||
/* 212: Optional parameters
|
||||
(actual length dependent on MTU). */
|
||||
};
|
||||
|
@@ -1399,12 +1399,17 @@ fqdn6_universe_decode(struct option_state *options,
|
||||
struct universe *u);
|
||||
int append_option(struct data_string *dst, struct universe *universe,
|
||||
struct option *option, struct data_string *src);
|
||||
int store_options PROTO ((int *, unsigned char *, unsigned, struct packet *,
|
||||
struct lease *, struct client_state *,
|
||||
struct option_state *,
|
||||
struct option_state *, struct binding_scope **,
|
||||
unsigned *, int, unsigned, unsigned,
|
||||
int, const char *));
|
||||
int
|
||||
store_options(int *ocount,
|
||||
unsigned char *buffer, unsigned buflen, unsigned index,
|
||||
struct packet *packet, struct lease *lease,
|
||||
struct client_state *client_state,
|
||||
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 *,
|
||||
const int *, struct data_string *);
|
||||
int format_has_text(const char *);
|
||||
|
@@ -218,7 +218,7 @@ void bootp (packet)
|
||||
lookup_option (&server_universe, options,
|
||||
SV_ALWAYS_REPLY_RFC1048), MDL))) {
|
||||
memcpy (outgoing.raw -> options,
|
||||
packet -> raw -> options, DHCP_OPTION_LEN);
|
||||
packet -> raw -> options, DHCP_MAX_OPTION_LEN);
|
||||
outgoing.packet_length = BOOTP_MIN_LEN;
|
||||
} else {
|
||||
|
||||
|
Reference in New Issue
Block a user