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:
@@ -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);
|
||||||
|
470
common/options.c
470
common/options.c
@@ -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.
|
||||||
|
@@ -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). */
|
||||||
};
|
};
|
||||||
|
@@ -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 *);
|
||||||
|
@@ -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 {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user