Perform length and type checking in ifchange.c:fill_options.c().

This commit is contained in:
Nicholas J. Kain 2011-03-30 10:13:34 -04:00
parent 1437f520ca
commit 7c32f968c9
3 changed files with 80 additions and 38 deletions

View File

@ -57,26 +57,39 @@ static int sprintip(char *dest, size_t size, char *pre, unsigned char *ip)
/* Fill dest with the text of option 'option'. */
/* Returns 0 if successful, -1 if nothing was filled in. */
static int fill_options(char *dest, unsigned char *option,
struct dhcp_option *type_p, unsigned int maxlen)
static int fill_options(char *dest, unsigned char *option, ssize_t optlen,
struct dhcp_option *type_p, unsigned int maxlen)
{
int type, optlen;
uint16_t val_u16;
int16_t val_s16;
char *odest;
enum option_type type = type_p->type;
ssize_t typelen = option_length(type);
uint32_t val_u32;
int32_t val_s32;
char *odest;
uint16_t val_u16;
int16_t val_s16;
uint8_t code = type_p->code;
if (!option)
return -1;
if (optlen != typelen) {
if (option_valid_list(code)) {
if ((optlen % typelen)) {
log_warning("Bad data received - option list size mismatch: code=0x%02x proplen=0x%02x optlen=0x%02x",
code, typelen, optlen);
return -1;
}
} else {
log_warning("Bad data received - option size mismatch: code=0x%02x proplen=0x%02x optlen=0x%02x",
code, typelen, optlen);
return -1;
}
}
int len = option[-1]; // XXX: WTF ugly as all hell
odest = dest;
dest += snprintf(dest, maxlen, "%s=", type_p->name);
type = type_p->type;
optlen = option_lengths[type];
for(;;) {
switch (type) {
case OPTION_IP: /* Works regardless of host byte order. */
@ -112,9 +125,11 @@ static int fill_options(char *dest, unsigned char *option,
memcpy(dest, option, len);
dest[len] = '\0';
return 0; /* Short circuit this case */
case OPTION_NONE:
return 0;
}
option += optlen;
len -= optlen;
option += typelen;
len -= typelen;
if (len <= 0)
break;
*(dest++) = ':';
@ -189,7 +204,7 @@ static void translate_option(int sockfd, struct dhcpMessage *packet,
memset(buf2, '\0', sizeof(buf2));
p = get_option(packet, code, &optlen);
if (fill_options(buf2, p, opt, sizeof buf2 - 1) == -1)
if (fill_options(buf2, p, optlen, opt, sizeof buf2 - 1) == -1)
return;
snprintf(buf, sizeof buf, "%s:", buf2);
for (i = 0; i < 256; i++) {

View File

@ -49,20 +49,57 @@ struct dhcp_option options[] = {
{"maxsize" , OPTION_U16, 0x39},
{"tftp" , OPTION_STRING, 0x42},
{"bootfile" , OPTION_STRING, 0x43},
{"" , 0x00, 0x00}
{"" , OPTION_NONE, 0x00}
};
/* Lengths of the different option types */
int option_lengths[] = {
[OPTION_IP] = 4,
[OPTION_STRING] = 1,
[OPTION_U8] = 1,
[OPTION_U16] = 2,
[OPTION_S16] = 2,
[OPTION_U32] = 4,
[OPTION_S32] = 4
// List of options that will be sent on the parameter request list to the
// remote DHCP server.
static unsigned char req_opts[] = {
DHCP_SUBNET,
DHCP_ROUTER,
DHCP_DNS_SERVER,
DHCP_HOST_NAME,
DHCP_DOMAIN_NAME,
DHCP_BROADCAST,
0x00
};
static unsigned char list_opts[] = {
DHCP_ROUTER,
DHCP_TIME_SERVER,
DHCP_NAME_SERVER,
DHCP_DNS_SERVER,
DHCP_LOG_SERVER,
DHCP_COOKIE_SERVER,
DHCP_LPR_SERVER,
DHCP_NTP_SERVER,
DHCP_WINS_SERVER,
0x00
};
uint8_t option_length(enum option_type type)
{
switch (type) {
case OPTION_IP: return 4;
case OPTION_STRING: return 1; // XXX ?
case OPTION_U8: return 1;
case OPTION_U16: return 2;
case OPTION_S16: return 2;
case OPTION_U32: return 4;
case OPTION_S32: return 4;
default: return 0;
}
}
int option_valid_list(uint8_t code)
{
int i;
for (i = 0; i < sizeof list_opts; ++i)
if (list_opts[i] == code)
return 1;
return 0;
}
size_t sizeof_option(unsigned char code, size_t datalen)
{
if (code == DHCP_PADDING || code == DHCP_END)
@ -229,7 +266,7 @@ int add_simple_option(unsigned char *optionptr, unsigned char code,
for (i = 0; options[i].code; i++)
if (options[i].code == code) {
length = option_lengths[(size_t)options[i].type];
length = option_length(options[i].type);
}
log_line("aso(): code=0x%02x length=0x%02x", code, length);
@ -252,18 +289,6 @@ int add_simple_option(unsigned char *optionptr, unsigned char code,
return add_option_string(optionptr, option);
}
// List of options that will be sent on the parameter request list to the
// remote DHCP server.
static unsigned char req_opts[] = {
DHCP_SUBNET,
DHCP_ROUTER,
DHCP_DNS_SERVER,
DHCP_HOST_NAME,
DHCP_DOMAIN_NAME,
DHCP_BROADCAST,
0x00
};
/* Add a paramater request list for stubborn DHCP servers. Don't do bounds */
/* checking here because it goes towards the head of the packet. */
void add_requests(struct dhcpMessage *packet)

View File

@ -51,8 +51,9 @@
#define DHCP_WPAD 0xfc
#define DHCP_END 0xff
enum {
OPTION_IP=1,
enum option_type {
OPTION_NONE = 0,
OPTION_IP,
OPTION_STRING,
OPTION_U8,
OPTION_U16,
@ -63,13 +64,14 @@ enum {
struct dhcp_option {
char name[10];
char type;
enum option_type type;
unsigned char code;
};
extern struct dhcp_option options[];
extern int option_lengths[];
uint8_t option_length(enum option_type type);
int option_valid_list(uint8_t code);
size_t sizeof_option(unsigned char code, size_t datalen);
size_t set_option(unsigned char *buf, size_t buflen, unsigned char code,
unsigned char *optdata, size_t datalen);